From 257d312a580e7c5d5df5749fafbc9471355a08d1 Mon Sep 17 00:00:00 2001 From: Koen Bussemaker Date: Wed, 10 Apr 2024 20:14:21 +0200 Subject: [PATCH 001/107] Fix #12228, Fix #12231: CheckShipReverse only restricts path when it has to --- src/pathfinder/yapf/yapf_ship.cpp | 110 +++++++++++++----------------- 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index 85f05747e5..57d5e9d877 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -172,6 +172,14 @@ public: return 'w'; } + /** Returns a random trackdir out of a set of trackdirs. */ + static Trackdir GetRandomTrackdir(TrackdirBits trackdirs) + { + const int strip_amount = RandomRange(CountBits(trackdirs)); + for (int s = 0; s < strip_amount; ++s) RemoveFirstTrackdir(&trackdirs); + return FindFirstTrackdir(trackdirs); + } + /** Returns a random tile/trackdir that can be reached from the current tile/trackdir, or tile/INVALID_TRACK if none is available. */ static std::pair GetRandomFollowUpTileTrackdir(const Ship *v, TileIndex tile, Trackdir dir) { @@ -180,17 +188,15 @@ public: TrackdirBits dirs = follower.m_new_td_bits; const TrackdirBits dirs_without_90_degree = dirs & ~TrackdirCrossesTrackdirs(dir); if (dirs_without_90_degree != TRACKDIR_BIT_NONE) dirs = dirs_without_90_degree; - const int strip_amount = RandomRange(CountBits(dirs)); - for (int s = 0; s < strip_amount; ++s) RemoveFirstTrackdir(&dirs); - return { follower.m_new_tile, FindFirstTrackdir(dirs) }; + return { follower.m_new_tile, GetRandomTrackdir(dirs) }; } return { follower.m_new_tile, INVALID_TRACKDIR }; } /** Creates a random path, avoids 90 degree turns. */ - static Trackdir CreateRandomPath(const Ship *v, Trackdir dir, ShipPathCache &path_cache, int path_length) + static Trackdir CreateRandomPath(const Ship *v, ShipPathCache &path_cache, int path_length) { - std::pair tile_dir = { v->tile, dir }; + std::pair tile_dir = { v->tile, v->GetVehicleTrackdir()}; for (int i = 0; i < path_length; ++i) { tile_dir = GetRandomFollowUpTileTrackdir(v, tile_dir.first, tile_dir.second); if (tile_dir.second == INVALID_TRACKDIR) break; @@ -204,19 +210,14 @@ public: return result; } - static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, bool &path_found, ShipPathCache &path_cache) + static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, TrackdirBits forward_dirs, TrackdirBits reverse_dirs, + bool &path_found, ShipPathCache &path_cache, Trackdir &best_origin_dir) { - const Trackdir trackdir = v->GetVehicleTrackdir(); - assert(IsValidTrackdir(trackdir)); - - /* Convert origin trackdir to TrackdirBits. */ - const TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir); - const std::vector high_level_path = YapfShipFindWaterRegionPath(v, tile, NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1); if (high_level_path.empty()) { path_found = false; /* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */ - return CreateRandomPath(v, trackdir, path_cache, SHIP_LOST_PATH_LENGTH); + return CreateRandomPath(v, path_cache, SHIP_LOST_PATH_LENGTH); } /* Try one time without restricting the search area, which generally results in better and more natural looking paths. @@ -226,7 +227,7 @@ public: Tpf pf(MAX_SHIP_PF_NODES); /* Set origin and destination nodes */ - pf.SetOrigin(v->tile, trackdirs); + pf.SetOrigin(v->tile, forward_dirs | reverse_dirs); pf.SetDestination(v); const bool is_intermediate_destination = static_cast(high_level_path.size()) >= NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1; if (is_intermediate_destination) pf.SetIntermediateDestination(high_level_path.back()); @@ -239,14 +240,16 @@ public: path_found = pf.FindPath(v); Node *node = pf.GetBestNode(); if (attempt == 0 && !path_found) continue; // Try again with restricted search area. - if (!path_found || node == nullptr) return GetRandomFollowUpTileTrackdir(v, v->tile, trackdir).second; + + /* Make the ship move around aimlessly. This prevents repeated pathfinder calls and clearly indicates that the ship is lost. */ + if (!path_found) return CreateRandomPath(v, path_cache, SHIP_LOST_PATH_LENGTH); /* Return only the path within the current water region if an intermediate destination was returned. If not, cache the entire path * to the final destination tile. The low-level pathfinder might actually prefer a different docking tile in a nearby region. Without * caching the full path the ship can get stuck in a loop. */ const WaterRegionPatchDesc end_water_patch = GetWaterRegionPatchInfo(node->GetTile()); - const WaterRegionPatchDesc start_water_patch = GetWaterRegionPatchInfo(tile); - assert(start_water_patch == high_level_path.front()); + assert(GetWaterRegionPatchInfo(tile) == high_level_path.front()); + const WaterRegionPatchDesc start_water_patch = high_level_path.front(); while (node->m_parent) { const WaterRegionPatchDesc node_water_patch = GetWaterRegionPatchInfo(node->GetTile()); @@ -262,10 +265,18 @@ public: } node = node->m_parent; } + assert(node->GetTile() == v->tile); + + /* Return INVALID_TRACKDIR to trigger a ship reversal if that is the best option. */ + best_origin_dir = node->GetTrackdir(); + if ((TrackdirToTrackdirBits(best_origin_dir) & forward_dirs) == TRACKDIR_BIT_NONE) { + path_cache.clear(); + return INVALID_TRACKDIR; + } /* A empty path means we are already at the destination. The pathfinder shouldn't have been called at all. * Return a random reachable trackdir to hopefully nudge the ship out of this strange situation. */ - if (path_cache.empty()) return GetRandomFollowUpTileTrackdir(v, v->tile, trackdir).second; + if (path_cache.empty()) return CreateRandomPath(v, path_cache, 1); /* Take out the last trackdir as the result. */ const Trackdir result = path_cache.front(); @@ -284,52 +295,30 @@ public: * Check whether a ship should reverse to reach its destination. * Called when leaving depot. * @param v Ship. - * @param tile Current position. - * @param td1 Forward direction. - * @param td2 Reverse direction. * @param trackdir [out] the best of all possible reversed trackdirs. * @return true if the reverse direction is better. */ - static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2, Trackdir *trackdir) + static bool CheckShipReverse(const Ship *v, Trackdir *trackdir) { - const std::vector high_level_path = YapfShipFindWaterRegionPath(v, tile, NUMBER_OR_WATER_REGIONS_LOOKAHEAD + 1); - if (high_level_path.empty()) { - if (trackdir) *trackdir = INVALID_TRACKDIR; - return false; - } + bool path_found = false; + ShipPathCache dummy_cache; + Trackdir best_origin_dir = INVALID_TRACKDIR; - /* Create pathfinder instance. */ - Tpf pf(MAX_SHIP_PF_NODES); - /* Set origin and destination nodes. */ if (trackdir == nullptr) { - pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2)); + /* The normal case, typically called when ships leave a dock. */ + const Trackdir reverse_dir = ReverseTrackdir(v->GetVehicleTrackdir()); + const TrackdirBits forward_dirs = TrackdirToTrackdirBits(v->GetVehicleTrackdir()); + const TrackdirBits reverse_dirs = TrackdirToTrackdirBits(reverse_dir); + (void)ChooseShipTrack(v, v->tile, forward_dirs, reverse_dirs, path_found, dummy_cache, best_origin_dir); + return path_found && best_origin_dir == reverse_dir; } else { - DiagDirection entry = ReverseDiagDir(VehicleExitDir(v->direction, v->state)); - TrackdirBits rtds = DiagdirReachesTrackdirs(entry) & TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0, entry)); - pf.SetOrigin(tile, rtds); + /* This gets called when a ship suddenly can't move forward, e.g. due to terraforming. */ + const DiagDirection entry = ReverseDiagDir(VehicleExitDir(v->direction, v->state)); + const TrackdirBits reverse_dirs = DiagdirReachesTrackdirs(entry) & TrackStatusToTrackdirBits(GetTileTrackStatus(v->tile, TRANSPORT_WATER, 0, entry)); + (void)ChooseShipTrack(v, v->tile, TRACKDIR_BIT_NONE, reverse_dirs, path_found, dummy_cache, best_origin_dir); + *trackdir = path_found && best_origin_dir != INVALID_TRACKDIR ? best_origin_dir : GetRandomTrackdir(reverse_dirs); + return true; } - pf.SetDestination(v); - if (high_level_path.size() > 1) pf.SetIntermediateDestination(high_level_path.back()); - pf.RestrictSearch(high_level_path); - - /* Find best path. */ - if (!pf.FindPath(v)) return false; - - Node *pNode = pf.GetBestNode(); - if (pNode == nullptr) return false; - - /* Path was found, walk through the path back to the origin. */ - while (pNode->m_parent != nullptr) { - pNode = pNode->m_parent; - } - - Trackdir best_trackdir = pNode->GetTrackdir(); - if (trackdir != nullptr) { - *trackdir = best_trackdir; - } else { - assert(best_trackdir == td1 || best_trackdir == td2); - } - return best_trackdir != td1; } }; @@ -437,14 +426,13 @@ struct CYapfShip : CYapfTGetVehicleTrackdir()); + const Trackdir td_ret = CYapfShip::ChooseShipTrack(v, tile, origin_dirs, TRACKDIR_BIT_NONE, path_found, path_cache, best_origin_dir); return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK; } bool YapfShipCheckReverse(const Ship *v, Trackdir *trackdir) { - Trackdir td = v->GetVehicleTrackdir(); - Trackdir td_rev = ReverseTrackdir(td); - TileIndex tile = v->tile; - return CYapfShip::CheckShipReverse(v, tile, td, td_rev, trackdir); + return CYapfShip::CheckShipReverse(v, trackdir); } From 018326321cef0468855bb9f37622ef948e002ab4 Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 17 Apr 2024 04:40:56 +0000 Subject: [PATCH 002/107] Update: Translations from eints english (us): 5 changes by 2TallTyler latvian: 1 change by lexuslatvia --- src/lang/afrikaans.txt | 1 + src/lang/arabic_egypt.txt | 1 + src/lang/basque.txt | 1 + src/lang/belarusian.txt | 1 + src/lang/brazilian_portuguese.txt | 1 + src/lang/bulgarian.txt | 1 + src/lang/catalan.txt | 1 + src/lang/chuvash.txt | 1 + src/lang/croatian.txt | 1 + src/lang/czech.txt | 1 + src/lang/danish.txt | 1 + src/lang/dutch.txt | 1 + src/lang/english_AU.txt | 1 + src/lang/english_US.txt | 6 ++++++ src/lang/esperanto.txt | 1 + src/lang/estonian.txt | 1 + src/lang/faroese.txt | 1 + src/lang/finnish.txt | 1 + src/lang/french.txt | 1 + src/lang/frisian.txt | 1 + src/lang/gaelic.txt | 1 + src/lang/galician.txt | 1 + src/lang/german.txt | 1 + src/lang/greek.txt | 1 + src/lang/hebrew.txt | 1 + src/lang/hindi.txt | 1 + src/lang/hungarian.txt | 1 + src/lang/icelandic.txt | 1 + src/lang/ido.txt | 1 + src/lang/indonesian.txt | 1 + src/lang/irish.txt | 1 + src/lang/italian.txt | 1 + src/lang/japanese.txt | 1 + src/lang/korean.txt | 1 + src/lang/latin.txt | 1 + src/lang/latvian.txt | 2 ++ src/lang/lithuanian.txt | 1 + src/lang/luxembourgish.txt | 1 + src/lang/macedonian.txt | 1 + src/lang/malay.txt | 1 + src/lang/maltese.txt | 1 + src/lang/marathi.txt | 1 + src/lang/norwegian_bokmal.txt | 1 + src/lang/norwegian_nynorsk.txt | 1 + src/lang/persian.txt | 1 + src/lang/polish.txt | 1 + src/lang/portuguese.txt | 1 + src/lang/romanian.txt | 1 + src/lang/russian.txt | 1 + src/lang/serbian.txt | 1 + src/lang/simplified_chinese.txt | 1 + src/lang/slovak.txt | 1 + src/lang/slovenian.txt | 1 + src/lang/spanish.txt | 1 + src/lang/spanish_MX.txt | 1 + src/lang/swedish.txt | 1 + src/lang/tamil.txt | 1 + src/lang/thai.txt | 1 + src/lang/traditional_chinese.txt | 1 + src/lang/turkish.txt | 1 + src/lang/ukrainian.txt | 1 + src/lang/urdu.txt | 1 + src/lang/vietnamese.txt | 1 + src/lang/welsh.txt | 1 + 64 files changed, 70 insertions(+) diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index ce69bbe327..3d08a12588 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -4624,6 +4624,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Verander STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Geen voertuie is op die oomblik beskikbaar nie STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Begin na {DATE_SHORT} of gebruik 'n NewGRF wat voertuie vroeër beskikbaar stel + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan nie trein forseer om sein te vermy op gevaar... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan nie rigting van trein verander nie... diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 184010a6a3..2be1344d26 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -4418,6 +4418,7 @@ STR_ERROR_CAN_T_CLONE_VEHICLE_LIST :{WHITE}... لي STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}لن تتوافر اى وسائل نقل على اﻹطلاق STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}لا تتوافر اى آليه نقل بعد + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}لا يمكن السماح للقطار بالعبور من الاشارة في وضع الخطر STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}لا يمكن عكس اتجاة القطار... diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 7580ed6e94..cbf591f95d 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -4369,6 +4369,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Ez da ib STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Aldatu zure NewGRF konfigurazioa STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Ez dago ibilgailu erabilgarririk oraindik + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Ezin da trena seinalea pasatzera behartu, istripu arriskua... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ezin da trenaren norabidea aldatu... diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 3a1de5eaf2..73d9a197ed 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -5631,6 +5631,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Зьмя STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Няма даступных транспартных сродкаў STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Пачніце гульню пасьля {DATE_SHORT} або падключыце NewGRF з транспартам адпаведных часоў. + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Немагчыма іґнараваць сыґнал. Небясьпечна... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Не атрымалася завярнуць цягнік... diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 9ba9130d8c..860a5f0184 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -5287,6 +5287,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Modifiqu STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Não existem veículos disponíveis ainda STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Inicie um novo jogo depois de {DATE_SHORT} ou utilize um NewGRF que forneça veículos iniciais + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Não é possível fazer o trem passar o sinal em perigo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Não é possível inverter a direção do trem... diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index 0d9efe83bd..b432c9e60a 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -4654,6 +4654,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Пром STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Няма налични превозни средства все още STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Започни нова игра след {DATE_SHORT} или използвай NewGRF , който показва ранни превозни средства + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Влака не може да пропусне сигнала при опасност... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Не може да обърне посоката на влак... diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index e40ab9c7e5..5da45529ba 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -5287,6 +5287,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Canvia l STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Encara no hi ha vehicles disponibles STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Inicieu una partida nova després de {DATE_SHORT} o useu un NewGRF que proporcioni vehicles primerencs. + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}No pots fer que un tren passi d'una senyal amb perill... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}No es pot invertir la direcció del tren... diff --git a/src/lang/chuvash.txt b/src/lang/chuvash.txt index 36c2e5f642..1bd4cd3df0 100644 --- a/src/lang/chuvash.txt +++ b/src/lang/chuvash.txt @@ -1709,6 +1709,7 @@ STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Ҫул + # Specific vehicle errors diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 00c09c6dc6..6435b15c58 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -4812,6 +4812,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Promijen STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Još nema dostupnih vozila STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Pokreni novu igru nakon {DATE_SHORT} ili upotrijebi NewGRF koji daje vrlo rana vozila + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nije moguće natjerati vlak da ignorira signale dok traje opasnost... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nije moguće promijeniti smjer vlaka... diff --git a/src/lang/czech.txt b/src/lang/czech.txt index 7b83851a3c..47af6fe005 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -5376,6 +5376,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zmeň na STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Zatím nejsou dostupná žádná vozidla STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Začít hru po {DATE_SHORT} nebo použít NewGRF, která zajistí dřívější vozidla + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nelze nechat vlak projet semafory v nebezpečí... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nelze obrátit vlak... diff --git a/src/lang/danish.txt b/src/lang/danish.txt index d0a9398d6b..ad5dad7ec9 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -5286,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Skift di STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Ingen køretøjer er tilgængelige endnu STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start et nyt spil efter {DATE_SHORT} eller brug en NewGRF der giver tidlige køretøjer + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan ikke få toget til at passere signalet... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan ikke vende retningen af toget... diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 25fb25b497..bea3abf06e 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -5286,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Pas je N STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nog geen voertuigen beschikbaar STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE} Start een nieuw spel na {DATE_SHORT} of gebruik een NewGRF dat in vroege voertuigen voorziet + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan trein niet het sein laten passeren bij gevaar... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan de richting van de trein niet omdraaien... diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index f71ba405c9..f432d6d71b 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -5286,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change y STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF which provides early vehicles + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train... diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 9c28e0f7b0..f9ffd8aaf2 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -3488,6 +3488,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Road type STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal) # Sprite aligner window +STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Aligning sprite: ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Aligning sprite: Action 0xA, {COMMA} ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Aligning sprite: Action 0x5, type {HEX}, {COMMA} ({STRING}:{NUM}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolor/font sprites and wrapping around from the last sprite to the first STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite @@ -3496,6 +3499,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolor/font sprites and wrapping around from the first sprite to the last STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets. Ctrl+Click to move the sprite eight units at a time +STR_SPRITE_ALIGNER_SPRITE :{STRING}:{NUM} ###length 2 STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Offset centered @@ -5282,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change y STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early vehicles + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train... @@ -5832,6 +5837,7 @@ STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING1 :{STRING} STR_JUST_STRING2 :{STRING} +STR_JUST_STRING4 :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index a9c026defe..118a9baa90 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -5144,6 +5144,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Ŝanĝu STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Neniuj veturiloj dume haveblas STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Komencu novan ludon post {DATE_SHORT} aŭ uzu NewGRF-on kiu havebligas frutempajn veturilojn + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Ne povas igi vagonaron transiri signalon je danĝero... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ne povas inversigi direkton de vagonaro... diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index efcdc634d5..ed67e64d0b 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -5334,6 +5334,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Muuda Ne STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Sõidukeid ei ole veel saadaval STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Alusta mängu pärast {DATE_SHORT} või kasuta NewGRF-i, milles on varasemaid sõidukeid + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Rongi ei saa ohu korral sundida signaale eirama... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ei saa rongi ümber pöörata. diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 5de884b32e..5e6b384a67 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -4024,6 +4024,7 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... akfa + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kann ikki fáa tok at fara framvið jarnbreytatekin tá vandi er... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kann ikki venda toki vi... diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 9e618188f2..017948e152 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -5286,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Muuta Ne STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Kulkuneuvoja ei ole vielä saatavilla STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Aloita peli {DATE_SHORT} jälkeen tai käytä NewGRF:ää joka tarjoaa aikaisempia kulkuneuvoja + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Junaa ei voi pakottaa jatkamaan punaisen opastimen ohi... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Junan suuntaa ei voi kääntää... diff --git a/src/lang/french.txt b/src/lang/french.txt index 383c102faf..b67f2b1132 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -5287,6 +5287,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Modifier STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Il n'y a pas encore de véhicules disponibles STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Commencer un nouvelle partie après {DATE_SHORT} ou utiliser un NewGRF qui propose des véhicules plus tôt + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Impossible de forcer le train à avancer sous le danger... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Impossible de faire faire demi-tour... diff --git a/src/lang/frisian.txt b/src/lang/frisian.txt index 71055270df..e32bf24f5c 100644 --- a/src/lang/frisian.txt +++ b/src/lang/frisian.txt @@ -4205,6 +4205,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Feroarje STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Der binne noch gjin fiertugen beskikber STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Begjin in nij spul nei {DATE_SHORT} of brûk in NewGRF dy't earder fiertugen beskikber stelt + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kin trein gjin sein foarby ride litte at dizze gefaar oanjout... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kin rydrjochting fan de trein net oanpasse diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index 11805cc18f..88cb7c19d8 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -4761,6 +4761,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Atharrai STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Chan eil carbad ri fhaighinn fhathast STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Tòisich geama ùr às dèidh {DATE_SHORT} no chleachd NewGRF a bheir carbadan tràtha dhut + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Chan urrainn dhut toirt air trèanaichean dol seachad air comharra fo chunnart... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Chan urrainn dhan trèana tilleadh... diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 15754aa2b0..7d04ac030f 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -5279,6 +5279,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Cambia a STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Aínda non hai vehículos dispoñíbeis STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Comezar unha partida nova a partires de {DATE_SHORT} ou empregar un NewGRF que proporcione vehículos antigos + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Non se pode facer que o tren rebase un sinal en perigo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}No se pode cambia-lo sentido do tren... diff --git a/src/lang/german.txt b/src/lang/german.txt index 9b3bcd883e..16fb7581fc 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -5281,6 +5281,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Bitte di STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Noch keine Fahrzeuge verfügbar STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Ein neues Spiel nach {DATE_SHORT} beginnen oder ein NewGRF-Fahrzeugset mit früher verfügbaren Fahrzeugen verwenden + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Der Zug kann das Signal nicht gefahrlos passieren ... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Die Zugbewegung kann nicht umgekehrt werden ... diff --git a/src/lang/greek.txt b/src/lang/greek.txt index f14aadb289..ea3dad2136 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -5386,6 +5386,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Αλλά STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Κανένα όχημα δεν είναι διαθέσιμο ακόμη STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Ξεκινήστε ένα νέο παιχνίδι αργότερα από {DATE_SHORT} η χρησιμοποιήστε ένα NewGRF το οποίο προσφέρει νωρίτερα οχήματα + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Δεν μπορεί το τρένο να περάσει σήμα με κίνδυνο... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Δεν αντιστρέφεται η κατεύθυνση του τρένου... diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index bc66be2033..e92de862c5 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -4687,6 +4687,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}שנה STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}כלי תחבורה עדיין לא זמינים STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}התחל משחק חדש אחרי {DATE_SHORT} או השתמש ב-NewGRF המכיל כלי תחבורה קדומים + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}לא ניתן להכריח את הרכבת לעבור ברמזור בעת סכנה... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}לא ניתן להפוך את כיוון הנסיעה של הרכבת... diff --git a/src/lang/hindi.txt b/src/lang/hindi.txt index 30c1dabb8e..534b54a7cc 100644 --- a/src/lang/hindi.txt +++ b/src/lang/hindi.txt @@ -1574,6 +1574,7 @@ STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}रे + # Specific vehicle errors STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}ट्रेन की दिशा उलट नहीं सकते... diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 59203dde4b..a24baec0e5 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -5341,6 +5341,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Változt STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Még nincsenek elérhető járművek STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Indíts új játékot {DATE_SHORT} után, vagy használj olyan NewGRF-et, ami tartalmaz megfelelően korai járműveket! + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nem haladhatja meg a vonat a megállj jelzést... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nem fordíthatod meg a vonatot... diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 5ba52905e3..09d9780897 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -4255,6 +4255,7 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... öku STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Engin farartæki verða í boði STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Breyta NewGRF stillingunum þínum + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Get ekki látið lest fara framhjá hættumerki... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Get ekki snúið lest við... diff --git a/src/lang/ido.txt b/src/lang/ido.txt index 0ba0d4e163..ac7b50ddad 100644 --- a/src/lang/ido.txt +++ b/src/lang/ido.txt @@ -1600,6 +1600,7 @@ STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Tro mult + # Specific vehicle errors diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index 177b0d2eeb..99fb0fc61e 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -5161,6 +5161,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Tukarkan STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Belum ada kendaraan yang tersedia saat ini STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Mulai permainan baru setelah {DATE_SHORT} atau gunakan NewGRF yang menyediakan kendaraan awal + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Tidak dapat memaksa kereta melanggar sinyal pada saat bahaya... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Tidak dapat memutar balik arah kereta... diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 90825adf64..d99a87a45b 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -4865,6 +4865,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Athraigh STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Níl aon fheithicil ar fáil fós STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Tosaigh cluiche nua ó {DATE_SHORT} ar aghaidh nó úsáid NewGRF lena gcuirtear feithiclí luath ar fáil + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Ní féidir iallach a chur ar thraein dul thar comhartha agus contúirt ann... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ní féidir treo na traenach a aisiompú... diff --git a/src/lang/italian.txt b/src/lang/italian.txt index 436d86cdb8..05195c2e51 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -5319,6 +5319,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Cambiare STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Non sono ancora disponibili veicoli STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Iniziare una nuova partita dopo il {DATE_SHORT} o utilizzare un NewGRF che fornisca veicoli a partire da date antecedenti + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Impossibile far passare al treno un segnale di pericolo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Impossibile invertire la direzione del treno... diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 115fced9f5..f3e61dccff 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -4988,6 +4988,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}利用可能な輸送機器がありません STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}{DATE_SHORT}年以降に開始するか、これより早い時期に輸送機器が開発されるNewGRFを利用して下さい + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}赤信号を無視させることができません STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}列車を反転できません diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 60ef5f39ab..c4cfb0abfe 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -5283,6 +5283,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}사용할 수 있는 차량이 하나도 없습니다 STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}{DATE_SHORT}년 이후에 새로운 게임을 시작하거나 차량이 더 빨리 개발되는 NewGRF을 사용하십시오. + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}너무 위험해서 신호를 무시할 수 없습니다... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}열차를 회차시킬 수 없습니다... diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 25bc4e2b3a..6bc1b21f6a 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -4752,6 +4752,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Muta con STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nulla vehicula adhuc parabilia sunt STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Incipe ludum post {DATE_SHORT} sive eligere idoneum NewGRF quod vehicula antiqua parat + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Non licet tramen impellere post signale... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Non licet tramini cursum reflectere... diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 9fb76b9052..6b759b0315 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -2578,6 +2578,7 @@ STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE} Jūsu s STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE} Jūsu servera nosaukums nav iestatīts. Nosaukumu var iestatīt vairākspēlētāju loga augšdaļā STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Klienta pārskats neatbilst servera pārskatam STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Nepareiza parole +STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST :{WHITE}Jūs neesat atļauto klientu sarakstā STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Serveris ir pilns STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Šajā serverī jums ir aizliegums STR_NETWORK_ERROR_KICKED :{WHITE}Jūs esat izmests no šīs spēles @@ -5295,6 +5296,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Mainiet STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Transportlīdzekļi vēl nav pieejami STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Sākt jaunu spēli pēc {DATE_SHORT} vai izmantot NewGRF, kas nodrošina agrīnus transporta līdzekļus + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Vilciens nevar šķērsot signālu briesmās... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Vilcienu nevar apgriezt... diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index 578359c1bb..798f207e21 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -5207,6 +5207,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Pakeiski STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Kol kas negalima įsigyti jokių transporto priemonių STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Pradėkite žaidimą vėliau, nei {DATE_SHORT}, arba įdiekite plėtinių, kurie leistų įsigyti transporto priemonių šiame ankstyvame laikotarpyje + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Neįmanoma priversti traukinio važiuoti nesaugiai... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Traukinio vaziavimo krypties pakeisti negalima... diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index ef41844276..f19ae7f54e 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -5277,6 +5277,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Änner d STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nach keng Gefierer verfügbar STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}En neit Spill no {DATE_SHORT} ufenken oder benotz en NewGRF den al Gefierer erlaabt + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kann den Zuch net bei Gefor durch d'Signal schécken... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kann d'Richtung vum Zuch net änneren... diff --git a/src/lang/macedonian.txt b/src/lang/macedonian.txt index 44bd9b1723..4a0d5308d8 100644 --- a/src/lang/macedonian.txt +++ b/src/lang/macedonian.txt @@ -2117,6 +2117,7 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... во + # Specific vehicle errors diff --git a/src/lang/malay.txt b/src/lang/malay.txt index 51a7aee810..5266a35664 100644 --- a/src/lang/malay.txt +++ b/src/lang/malay.txt @@ -4161,6 +4161,7 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... kend STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Mulakan permainan baru selepas {DATE_SHORT} atau gunakan NewGRF yang digunakan kenderaan terdahulu + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Keretapi tidak boleh melanggar isyarat kerana terdapat kemungkinan bahaya... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Keretapi tidak boleh ditukar arah... diff --git a/src/lang/maltese.txt b/src/lang/maltese.txt index 4c41075122..da063b328a 100644 --- a/src/lang/maltese.txt +++ b/src/lang/maltese.txt @@ -1468,6 +1468,7 @@ STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Hemm wis + # Specific vehicle errors STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ma tistax tbiddel id-direzzjoni tal-ferrovija... diff --git a/src/lang/marathi.txt b/src/lang/marathi.txt index dac56fa193..112edf8266 100644 --- a/src/lang/marathi.txt +++ b/src/lang/marathi.txt @@ -1867,6 +1867,7 @@ STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}पू + # Specific vehicle errors diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 3953b8868c..64a30700d5 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -5288,6 +5288,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Endre di STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Ingen kjøretøyer er tilgjengelig ennå STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Starte et nytt spill etter {DATE_SHORT}, eller bruke en NewGRF som inneholder tidlige kjøretøy + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan ikke tvinge tog til å passere signal ved fare... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan ikke reversere toget... diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index ed09582836..43ad419318 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -4396,6 +4396,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Byt NewG STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Det finst ikkje nokon køyretøy enno STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start spelet etter {DATE_SHORT} eller bruk ein GRF som har køyretøy frå tidlegare tider + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan ikkje tvinge tog til å passere signal ved fare... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan ikkje snu toget... diff --git a/src/lang/persian.txt b/src/lang/persian.txt index f08def6a82..00c2596bc2 100644 --- a/src/lang/persian.txt +++ b/src/lang/persian.txt @@ -3748,6 +3748,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}بطور STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}تنظیمات مربوط به NewGRF را تغییر دهید STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}هنوز خودرویی در دسترس نیست + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}در هنگام خطر نمی توان علامت عبور قطار را داد STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}جهت قطار را نمی شود تغییر داد... diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 3a0a8fd9fe..ae307a167f 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -5672,6 +5672,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zmień k STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Obecnie żaden pojazd nie jest dostępny STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Zacznij grę po {DATE_SHORT} albo użyj zestawu NewGRF, który zawiera wczesne pojazdy + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nie można przepuścić pociągu za sygnał, niebezpieczeństwo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nie można odwrócić kierunku jazdy pociągu... diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 31193cbcda..6c7e8b5904 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -5287,6 +5287,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Mudar a STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nenhum veículo ainda disponível STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Começar um novo jogo depois de {DATE_SHORT} ou utilizar um NewGRF que forneça veículos iniciais + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Não é possível fazer o comboio passar o sinal com perigo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Não é possível inverter a direcção do comboio... diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index ea9177a1dc..2d016ba1ad 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -5273,6 +5273,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Schimbă STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Niciun vehicul nu este disponibil încă STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Începe un joc nou după {DATE_SHORT} sau utilizează un NewGRF care oferă vehicule în avans + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nu se poate permite trenului să treacă în caz de pericol... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nu se poate schimba sensul de mers al trenului... diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 56dcbbf559..598bb83968 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -5473,6 +5473,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Изме STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Нет доступных транспортных средств STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Начните игру не ранее {DATE_SHORT} либо подключите NewGRF, добавляющий транспортные средства, использовавшиеся в это время. + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Невозможно игнорировать светофор. Опасно... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Невозможно развернуть поезд... diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index 83b03e555c..6ca88c3f00 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -5380,6 +5380,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Promeni STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nijedno vozilo još uvek nije dostupno STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Pokreni novu igru koja počinje posle {DATE_SHORT} ili koristi NewGRF koji omogućava ranija vozila + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nemoguć je prolaz voza na signal opasnosti... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}... vozilo je uništeno diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index c5c24441a1..4ca83af535 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -5283,6 +5283,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}请改 STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}暂时沒有可用的载具 STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}在{DATE_SHORT}后开始新游戏,或使用一款能提供早期载具的NewGRF + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}不能让列车冒险通过信号... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}不能命令列车调头... diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index 058d87d45a..8ce5a9f166 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -5348,6 +5348,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zmena va STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Zatiaľ nie sú dostupné žiadne vozidlá STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Začnite novú hru po {DATE_SHORT} alebo použite NewGRF, ktoré zabezpečí vozidlá v skoršom čase + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nemožno nechať vlak prejsť návestidlo ak hrozí nebezpečenstvo... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nemožno otočiť vlak naopak... diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index b8fa8435c9..c8149b0ebb 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -4645,6 +4645,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zamenjaj STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Ni še vozil na razpolago. STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Začni novo igro po {DATE_SHORT} ali uporabi NewGRF, ki vsebuje zgodnja vozila + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Ni mogoče, da vlak v nevarnosti pelje mimo signalov... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Ni mogoče spremeniti smeri vlaka... diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index e4921fda2c..0624ce69bd 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -5287,6 +5287,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Es neces STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}En esta fecha no hay vehículos disponibles STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Comienza una nueva partida después de {DATE_SHORT} o usa un NewGRF que provea vehículos más antiguos + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}No se puede pasar la señal en peligro al tren... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}No se puede cambiar la dirección... diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 8b734a5842..1753a04fde 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -5157,6 +5157,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Se debe STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Todavía no hay vehículos disponibles STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Se debe empezar una nueva partida después de {DATE_SHORT} o usar un NewGRF que proporcione vehículos más antiguos + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}El tren no puede rebasar la señal si está en peligro... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}No se puede cambiar la dirección del tren... diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 41607130c9..823870fc23 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -5286,6 +5286,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Ändra d STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Inga fordon är tillgängliga än STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Starta ett nytt spel efter {DATE_SHORT} eller använd en NewGRF som erbjuder tidiga fordon + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan inte tillåta tåg att passera signal under fara... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan inte byta tågets riktning... diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index 0556acd908..be2da27776 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -4871,6 +4871,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}தங STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}தற்போது எந்த வாகனங்களும் கிடையாது STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}{DATE_SHORT} இற்கு பிறகு புதிய ஆட்டம் ஒன்றினைத் தொடங்கு அல்லது NewGRF ஒன்றினைப் பயன்படுத்தி பிற்கால வாகனங்களைப் பயன்படுத்து + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}இரயில் சிக்னலைத் தாண்டிச் செல்ல முடியாது... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}இரயில் செல்லும் திசையினை திருப்ப முடியாது... diff --git a/src/lang/thai.txt b/src/lang/thai.txt index 421e65bb87..a9fd5a7a83 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -4601,6 +4601,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}เป STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}ยังไม่มียานพาหานะให้เลือก STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}เริ่มเกมหลังจาก {DATE_SHORT} หรือเลือกใช้งาน NewGRF ของยานพาหนะที่จัดเตรียมไว้ก่อนหน้านี้ + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}ไม่สามารถสั่งให้รถไฟวิ่งผ่านเสาอาณัติสัญญาณที่แสดงท่า "ห้าม"... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}ไม่สามารถกลับทิศขบวนรถไฟได้... diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index d0ee79f49f..27dd3f671c 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -5102,6 +5102,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}請修 STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}未有可用的車輛 STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}在{DATE_SHORT}後開始新遊戲,或使用提供早期車輛的NewGRF + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}無法讓列車通過險阻號誌... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}無法倒轉列車方向... diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index d4a3f1ce92..7945464b7c 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -5279,6 +5279,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Yeni New STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Henüz hiçbir araç kullanılabilir değil STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}{DATE_SHORT} sonra yeni bir oyun başlat veya erken araç sağlayan NewGRF kullan + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Tehlikedeki tren sinyali geçemez... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Tren çevrilemez... diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index 7eadb93497..496e385fbc 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -5424,6 +5424,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Змін STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Жоден вид транспорту ще не став доступним STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Починайте нову гру після {DATE_SHORT} або використовуйте NewGRF, в якому транспорт з’являється раніше + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Неможливо проїхати сигнал - небезпечно... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Неможливо розвернути поїзд... diff --git a/src/lang/urdu.txt b/src/lang/urdu.txt index 06c6d24238..521bbd13c4 100644 --- a/src/lang/urdu.txt +++ b/src/lang/urdu.txt @@ -2880,6 +2880,7 @@ STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}مرمت + # Specific vehicle errors diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 62dd744acd..1c6cfb73e6 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -5280,6 +5280,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Thay đ STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Chưa có phương tiện nào có sẵn STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Bắt đầu một màn chơi mới sau {DATE_SHORT} hoặc sử dụng một NewGRF cung cấp sớm phương tiện + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Không thể để tàu hoả qua tín hiệu đèn khi nguy hiểm... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Không thể đổi hướng đoàn tàu... diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index 87979e7e4e..40e7dcc914 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -5280,6 +5280,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Newid ei STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Dim cerbydau ar gael eto STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Dechreuwch gêm newydd wedi {DATE_SHORT} neu defnyddiwch NewGRF sy'n darparu cerbydau cynnar + # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Does dim modd gwneud i drên basio signal pan fo perygl... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Methu gwrthdroi'r trên... From b477a8458ceaf7f75b2c4c2665f96daeed75457f Mon Sep 17 00:00:00 2001 From: Paco Esteban Date: Wed, 17 Apr 2024 18:08:03 +0200 Subject: [PATCH 003/107] Codechange: Use arc4random_buf on random_func.cpp for OpenBSD --- src/core/random_func.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/random_func.cpp b/src/core/random_func.cpp index 971879dd38..355eeff616 100644 --- a/src/core/random_func.cpp +++ b/src/core/random_func.cpp @@ -97,7 +97,7 @@ void RandomBytesWithFallback(std::span buf) #if defined(_WIN32) auto res = BCryptGenRandom(nullptr, static_cast(buf.data()), static_cast(buf.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG); if (res >= 0) return; -#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) +#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) arc4random_buf(buf.data(), buf.size()); return; #elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))) From ef8eb66a2bb238c683dd358fca76d40250e13fb3 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 Apr 2024 18:54:50 +0100 Subject: [PATCH 004/107] Fix c38df2d58: Use VehicleID instead of pointer in map of vehicles to replace. (#12512) This affects the sort order, VehicleID is deterministic, Vehicle * is not. --- src/vehicle.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index c8fefff234..748ad84b7d 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -691,7 +691,7 @@ void ResetVehicleColourMap() * List of vehicles that should check for autoreplace this tick. * Mapping of vehicle -> leave depot immediately after autoreplace. */ -using AutoreplaceMap = std::map; +using AutoreplaceMap = std::map; static AutoreplaceMap _vehicles_to_autoreplace; void InitializeVehicles() @@ -921,7 +921,7 @@ Vehicle::~Vehicle() void VehicleEnteredDepotThisTick(Vehicle *v) { /* Vehicle should stop in the depot if it was in 'stopping' state */ - _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED); + _vehicles_to_autoreplace[v->index] = !(v->vehstatus & VS_STOPPED); /* We ALWAYS set the stopped state. Even when the vehicle does not plan on * stopping in the depot, so we stop it to ensure that it will not reserve @@ -1069,7 +1069,7 @@ void CallVehicleTicks() Backup cur_company(_current_company); for (auto &it : _vehicles_to_autoreplace) { - Vehicle *v = it.first; + Vehicle *v = Vehicle::Get(it.first); /* Autoreplace needs the current company set as the vehicle owner */ cur_company.Change(v->owner); @@ -1625,7 +1625,7 @@ void VehicleEnterDepot(Vehicle *v) cur_company.Restore(); if (cost.Failed()) { - _vehicles_to_autoreplace[v] = false; + _vehicles_to_autoreplace[v->index] = false; if (v->owner == _local_company) { /* Notify the user that we stopped the vehicle */ SetDParam(0, v->index); @@ -1647,7 +1647,7 @@ void VehicleEnterDepot(Vehicle *v) } if (v->current_order.GetDepotActionType() & ODATFB_HALT) { /* Vehicles are always stopped on entering depots. Do not restart this one. */ - _vehicles_to_autoreplace[v] = false; + _vehicles_to_autoreplace[v->index] = false; /* Invalidate last_loading_station. As the link from the station * before the stop to the station after the stop can't be predicted * we shouldn't construct it when the vehicle visits the next stop. */ From 0b9029b69c45553a9c8858b38cbd5764e8b0ea60 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Apr 2024 02:14:25 +0100 Subject: [PATCH 005/107] Fix: Station/industry nearby list checks in CheckCaches --- src/openttd.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/openttd.cpp b/src/openttd.cpp index 898ea24832..4314f5a97d 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1362,7 +1362,10 @@ static void CheckCaches() for (Town *t : Town::Iterate()) old_town_stations_near.push_back(t->stations_near); std::vector old_industry_stations_near; - for (Industry *ind : Industry::Iterate()) old_industry_stations_near.push_back(ind->stations_near); + for (Industry *ind : Industry::Iterate()) old_industry_stations_near.push_back(ind->stations_near); + + std::vector old_station_industries_near; + for (Station *st : Station::Iterate()) old_station_industries_near.push_back(st->industries_near); for (Station *st : Station::Iterate()) { for (GoodsEntry &ge : st->goods) { @@ -1388,13 +1391,17 @@ static void CheckCaches() Debug(desync, 2, "docking tile mismatch: tile {}", tile); } } + } - /* Check industries_near */ - IndustryList industries_near = st->industries_near; - st->RecomputeCatchment(); - if (st->industries_near != industries_near) { + Station::RecomputeCatchmentForAll(); + + /* Check industries_near */ + i = 0; + for (Station *st : Station::Iterate()) { + if (st->industries_near != old_station_industries_near[i]) { Debug(desync, 2, "station industries near mismatch: station {}", st->index); } + i++; } /* Check stations_near */ From 824687d1f0e090474922e0c21bae26b88409f8e9 Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Wed, 17 Apr 2024 14:42:49 -0400 Subject: [PATCH 006/107] Codefix: Don't mix signed and unsigned ints in unbunching calculations (#12514) --- src/vehicle.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 748ad84b7d..e441d3366d 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2512,7 +2512,7 @@ void Vehicle::LeaveUnbunchingDepot() SetWindowDirty(WC_VEHICLE_TIMETABLE, this->index); /* Find the average travel time of vehicles that we share orders with. */ - uint num_vehicles = 0; + int num_vehicles = 0; TimerGameTick::Ticks total_travel_time = 0; Vehicle *u = this->FirstShared(); @@ -2525,10 +2525,10 @@ void Vehicle::LeaveUnbunchingDepot() } /* Make sure we cannot divide by 0. */ - num_vehicles = std::max(num_vehicles, 1u); + num_vehicles = std::max(num_vehicles, 1); /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */ - TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1u); + TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1); TimerGameTick::TickCounter next_departure = TimerGameTick::counter + separation; /* Set the departure time of all vehicles that we share orders with. */ From 5878d09ef268c3a3b82c02703e312d665541dcfb Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Wed, 17 Apr 2024 15:03:53 -0400 Subject: [PATCH 007/107] Fix: Smooth outliers in unbunching round trip calculations (#12513) --- src/vehicle.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index e441d3366d..12941e7e83 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1666,7 +1666,14 @@ void VehicleEnterDepot(Vehicle *v) /* If we've entered our unbunching depot, record the round trip duration. */ if (v->current_order.GetDepotActionType() & ODATFB_UNBUNCH && v->depot_unbunching_last_departure > 0) { - v->round_trip_time = (TimerGameTick::counter - v->depot_unbunching_last_departure); + TimerGameTick::Ticks measured_round_trip = TimerGameTick::counter - v->depot_unbunching_last_departure; + if (v->round_trip_time == 0) { + /* This might be our first round trip. */ + v->round_trip_time = measured_round_trip; + } else { + /* If we have a previous trip, smooth the effects of outlier trip calculations caused by jams or other interference. */ + v->round_trip_time = Clamp(measured_round_trip, (v->round_trip_time / 2), ClampTo(v->round_trip_time * 2)); + } } v->current_order.MakeDummy(); From a02da5476ee7d9abf8708de0649a2dc6c662a56a Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Wed, 17 Apr 2024 15:04:16 -0400 Subject: [PATCH 008/107] Fix: Don't show train waiting for unbunching as waiting for free path (#12515) --- src/vehicle_gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 58ee59459e..6ec093a182 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -3118,12 +3118,12 @@ public: } else { // no train str = STR_VEHICLE_STATUS_STOPPED; } + } else if (v->IsInDepot() && v->IsWaitingForUnbunching()) { + str = STR_VEHICLE_STATUS_WAITING_UNBUNCHING; } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_TRAIN_STUCK; } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; - } else if (v->IsInDepot() && v->IsWaitingForUnbunching()) { - str = STR_VEHICLE_STATUS_WAITING_UNBUNCHING; } else { // vehicle is in a "normal" state, show current order if (mouse_over_start_stop) { if (v->vehstatus & VS_STOPPED) { From 1005c86c62f9bedc20102887bfc57131b26a6ed0 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Apr 2024 21:49:55 +0200 Subject: [PATCH 009/107] Codechange: record cache warnings with a "warning" prefix (#12518) --- src/network/network.cpp | 3 ++- src/newgrf_storage.cpp | 2 +- src/openttd.cpp | 24 ++++++++++++------------ src/pathfinder/yapf/yapf_rail.cpp | 8 ++++---- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/network/network.cpp b/src/network/network.cpp index 2b0a79ba16..f97a6c47b0 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -1210,7 +1210,8 @@ void NetworkGameLoop() assert(ret == 4); check_sync_state = true; } else if (strncmp(p, "msg: ", 5) == 0 || strncmp(p, "client: ", 8) == 0 || - strncmp(p, "load: ", 6) == 0 || strncmp(p, "save: ", 6) == 0) { + strncmp(p, "load: ", 6) == 0 || strncmp(p, "save: ", 6) == 0 || + strncmp(p, "warning: ", 9) == 0) { /* A message that is not very important to the log playback, but part of the log. */ #ifndef DEBUG_FAILED_DUMP_COMMANDS } else if (strncmp(p, "cmdf: ", 6) == 0) { diff --git a/src/newgrf_storage.cpp b/src/newgrf_storage.cpp index b071c3c743..ff309a66df 100644 --- a/src/newgrf_storage.cpp +++ b/src/newgrf_storage.cpp @@ -91,7 +91,7 @@ void AddChangedPersistentStorage(BasePersistentStorageArray *storage) /* Discard all temporary changes */ for (auto &it : *_changed_storage_arrays) { - Debug(desync, 1, "Discarding persistent storage changes: Feature {}, GrfID {:08X}, Tile {}", it->feature, BSWAP32(it->grfid), it->tile); + Debug(desync, 2, "warning: discarding persistent storage changes: Feature {}, GrfID {:08X}, Tile {}", it->feature, BSWAP32(it->grfid), it->tile); it->ClearChanges(); } _changed_storage_arrays->clear(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 4314f5a97d..fc6e60c4b1 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1248,7 +1248,7 @@ static void CheckCaches() uint i = 0; for (Town *t : Town::Iterate()) { if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { - Debug(desync, 2, "town cache mismatch: town {}", t->index); + Debug(desync, 2, "warning: town cache mismatch: town {}", t->index); } i++; } @@ -1262,7 +1262,7 @@ static void CheckCaches() i = 0; for (const Company *c : Company::Iterate()) { if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { - Debug(desync, 2, "infrastructure cache mismatch: company {}", c->index); + Debug(desync, 2, "warning: infrastructure cache mismatch: company {}", c->index); } i++; } @@ -1318,23 +1318,23 @@ static void CheckCaches() for (const Vehicle *u = v; u != nullptr; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { - Debug(desync, 2, "newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length); + Debug(desync, 2, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { - Debug(desync, 2, "vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length); + Debug(desync, 2, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - Debug(desync, 2, "train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); + Debug(desync, 2, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { - Debug(desync, 2, "train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); + Debug(desync, 2, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - Debug(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); + Debug(desync, 2, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length); } break; default: @@ -1384,11 +1384,11 @@ static void CheckCaches() } UpdateStationDockingTiles(st); if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) { - Debug(desync, 2, "station docking mismatch: station {}, company {}", st->index, st->owner); + Debug(desync, 2, "warning: station docking mismatch: station {}, company {}", st->index, st->owner); } for (TileIndex tile : ta) { if (docking_tiles[tile] != IsDockingTile(tile)) { - Debug(desync, 2, "docking tile mismatch: tile {}", tile); + Debug(desync, 2, "warning: docking tile mismatch: tile {}", tile); } } } @@ -1399,7 +1399,7 @@ static void CheckCaches() i = 0; for (Station *st : Station::Iterate()) { if (st->industries_near != old_station_industries_near[i]) { - Debug(desync, 2, "station industries near mismatch: station {}", st->index); + Debug(desync, 2, "warning: station industries near mismatch: station {}", st->index); } i++; } @@ -1408,14 +1408,14 @@ static void CheckCaches() i = 0; for (Town *t : Town::Iterate()) { if (t->stations_near != old_town_stations_near[i]) { - Debug(desync, 2, "town stations near mismatch: town {}", t->index); + Debug(desync, 2, "warning: town stations near mismatch: town {}", t->index); } i++; } i = 0; for (Industry *ind : Industry::Iterate()) { if (ind->stations_near != old_industry_stations_near[i]) { - Debug(desync, 2, "industry stations near mismatch: industry {}", ind->index); + Debug(desync, 2, "warning: industry stations near mismatch: industry {}", ind->index); } i++; } diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index e024cee323..9580086799 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -241,7 +241,7 @@ public: pf2.DisableCache(true); FindDepotData result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty); if (result1.tile != result2.tile || (result1.reverse != result2.reverse)) { - Debug(desync, 2, "CACHE ERROR: FindNearestDepotTwoWay() = [{}, {}]", + Debug(desync, 2, "warning: FindNearestDepotTwoWay cache mismatch: {} vs {}", result1.tile != INVALID_TILE ? "T" : "F", result2.tile != INVALID_TILE ? "T" : "F"); DumpState(pf1, pf2); @@ -325,7 +325,7 @@ public: pf2.DisableCache(true); result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false); if (result1 != result2) { - Debug(desync, 2, "CACHE ERROR: FindSafeTile() = [{}, {}]", result2 ? "T" : "F", result1 ? "T" : "F"); + Debug(desync, 2, "warning: FindSafeTile cache mismatch: {} vs {}", result2 ? "T" : "F", result1 ? "T" : "F"); DumpState(pf1, pf2); } } @@ -409,7 +409,7 @@ public: pf2.DisableCache(true); Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest); if (result1 != result2) { - Debug(desync, 2, "CACHE ERROR: ChooseRailTrack() = [{}, {}]", result1, result2); + Debug(desync, 2, "warning: ChooseRailTrack cache mismatch: {} vs {}", result1, result2); DumpState(pf1, pf2); } } @@ -476,7 +476,7 @@ public: pf2.DisableCache(true); bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty); if (result1 != result2) { - Debug(desync, 2, "CACHE ERROR: CheckReverseTrain() = [{}, {}]", result1 ? "T" : "F", result2 ? "T" : "F"); + Debug(desync, 2, "warning: CheckReverseTrain cache mismatch: {} vs {}", result1 ? "T" : "F", result2 ? "T" : "F"); DumpState(pf1, pf2); } } From a09749f6a69fbf83a8b38f778058b43af4c7f41f Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Apr 2024 21:51:36 +0200 Subject: [PATCH 010/107] Codefix: don't send desync=0 log messages to commands.log (#12517) They are only used during replay, and you want to see those in the console; not in the log. --- src/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index 02150379f7..d12265a099 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -110,7 +110,7 @@ void DumpDebugFacilityNames(std::back_insert_iterator &output_itera */ void DebugPrint(const char *category, int level, const std::string &message) { - if (strcmp(category, "desync") == 0) { + if (strcmp(category, "desync") == 0 && level != 0) { static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR); if (f == nullptr) return; From a0636d82006b22cc8d89cc127c78280216c485d2 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Apr 2024 22:01:58 +0200 Subject: [PATCH 011/107] Codechange: use infinite-fast-forward when rerunning command-log (#12519) --- src/network/network.cpp | 10 ++++++++-- src/network/network_internal.h | 13 ------------- src/video/dedicated_v.cpp | 1 - src/video/video_driver.hpp | 7 +++++++ 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/network/network.cpp b/src/network/network.cpp index f97a6c47b0..15f77a84d2 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -37,6 +37,9 @@ #include "../gfx_func.h" #include "../error.h" #include "../misc_cmd.h" +#ifdef DEBUG_DUMP_COMMANDS +# include "../fileio_func.h" +#endif #include #include #include @@ -44,8 +47,11 @@ #include "../safeguards.h" #ifdef DEBUG_DUMP_COMMANDS -#include "../fileio_func.h" -/** When running the server till the wait point, run as fast as we can! */ +/** Helper variable to make the dedicated server go fast until the (first) join. + * Used to load the desync debug logs, i.e. for reproducing a desync. + * There's basically no need to ever enable this, unless you really know what + * you are doing, i.e. debugging a desync. + * See docs/desync.txt for details. */ bool _ddc_fastforward = true; #endif /* DEBUG_DUMP_COMMANDS */ diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 66dea11be4..35adc68983 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -37,19 +37,6 @@ #define NETWORK_SEND_DOUBLE_SEED #endif /* RANDOM_DEBUG */ -/** - * Helper variable to make the dedicated server go fast until the (first) join. - * Used to load the desync debug logs, i.e. for reproducing a desync. - * There's basically no need to ever enable this, unless you really know what - * you are doing, i.e. debugging a desync. - * See docs/desync.txt for details. - */ -#ifdef DEBUG_DUMP_COMMANDS -extern bool _ddc_fastforward; -#else -#define _ddc_fastforward (false) -#endif /* DEBUG_DUMP_COMMANDS */ - typedef class ServerNetworkGameSocketHandler NetworkClientSocket; /** Status of the clients during joining. */ diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index c0c0fa2278..c620f44110 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -219,7 +219,6 @@ void VideoDriver_Dedicated::MainLoop() if (!_dedicated_forks) DedicatedHandleKeyInput(); this->DrainCommandQueue(); - ChangeGameSpeed(_ddc_fastforward); this->Tick(); this->SleepTillNextTick(); } diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 874198d465..72731f0113 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -16,6 +16,7 @@ #include "../gfx_func.h" #include "../settings_type.h" #include "../zoom_type.h" +#include "../network/network_func.h" #include #include #include @@ -311,6 +312,12 @@ protected: std::chrono::steady_clock::duration GetGameInterval() { +#ifdef DEBUG_DUMP_COMMANDS + /* When replaying, run as fast as we can. */ + extern bool _ddc_fastforward; + if (_ddc_fastforward) return std::chrono::microseconds(0); +#endif /* DEBUG_DUMP_COMMANDS */ + /* If we are paused, run on normal speed. */ if (_pause_mode) return std::chrono::milliseconds(MILLISECONDS_PER_TICK); /* Infinite speed, as quickly as you can. */ From 07b162ffc417962a826b81000c50504f580e9e12 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Apr 2024 22:05:45 +0200 Subject: [PATCH 012/107] Codechange: skip all commands of the past during desync replay (#12520) --- src/network/network.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/network/network.cpp b/src/network/network.cpp index 15f77a84d2..3cd1529bdb 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -1157,6 +1157,16 @@ void NetworkGameLoop() } } + /* Skip all entries in the command-log till we caught up with the current game again. */ + if (TimerGameEconomy::date > next_date || (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract > next_date_fract)) { + Debug(desync, 0, "Skipping to next command at {:08x}:{:02x}", next_date, next_date_fract); + if (cp != nullptr) { + delete cp; + cp = nullptr; + } + check_sync_state = false; + } + if (cp != nullptr || check_sync_state) break; char buff[4096]; From f7bd08001546a078ec6df014ccb77610bf8bc7eb Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Apr 2024 22:36:08 +0200 Subject: [PATCH 013/107] Codechange: improve desync documentation (#12521) --- docs/desync.md | 31 +++++++++++++++---------------- src/network/network.cpp | 2 +- src/network/network_func.h | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/desync.md b/docs/desync.md index 20003c9810..afbebb11c5 100644 --- a/docs/desync.md +++ b/docs/desync.md @@ -195,10 +195,11 @@ Last updated: 2014-02-23 'src/network/network_func.h'. (DEBUG_FAILED_DUMP_COMMANDS is explained later) - Put the 'commands-out.log' into the root save folder, and rename - it to 'commands.log'. - - Run 'openttd -D -d desync=3 -g startsavegame.sav'. - This replays the server log and creates new 'commands-out.log' - and 'dmp_cmds_*.sav' in your autosave folder. + it to 'commands.log'. Strip everything and including the "newgame" + entry from the log. + - Run 'openttd -D -d desync=0 -g startsavegame.sav'. + This replays the server log. Use "-d desync=3" to also create a + new 'commands-out.log' and 'dmp_cmds_*.sav' in your autosave folder. ## 3.2) Evaluation of the replay @@ -226,7 +227,7 @@ Last updated: 2014-02-23 savegames with your own ones from the replay. You can also comment/disable the 'NOT_REACHED' mentioned above, to get another 'dmp_cmds_*.sav' from the replay after the mismatch has already been detected. - See Section 3.2 on how to compare savegames. + See Section 3.3 on how to compare savegames. If the saves differ you have located the Desync between the last dmp_cmds that match and the first one that does not. The difference of the saves may point you in the direction of what causes it. @@ -252,16 +253,14 @@ Last updated: 2014-02-23 are replayed. Their internal state will thus not change in the replay and will differ. - To compare savegame more semantically, there exist some ugly hackish - tools at: - http://devs.openttd.org/~frosch/texts/zpipe.c - http://devs.openttd.org/~frosch/texts/printhunk.c + To compare savegame more semantically, easiest is to first export them + to a JSON format with for example: - The first one decompresses OpenTTD savegames. The second one creates - a textual representation of an uncompressed savegame, by parsing hunks - and arrays and such. With both tools you need to be a bit careful - since they work on stdin and stdout, which may not deal well with - binary data. + https://github.com/TrueBrain/OpenTTD-savegame-reader - If you have the textual representation of the savegames, you can - compare them with regular diff tools. + By running: + + python -m savegame_reader --export-json dmp_cmds_NNN.sav | jq . > NNN.json + + Now you can use any (JSON) diff tool to compare the two savegames in a + somewhat human readable way. diff --git a/src/network/network.cpp b/src/network/network.cpp index 3cd1529bdb..5eb64da827 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -51,7 +51,7 @@ * Used to load the desync debug logs, i.e. for reproducing a desync. * There's basically no need to ever enable this, unless you really know what * you are doing, i.e. debugging a desync. - * See docs/desync.txt for details. */ + * See docs/desync.md for details. */ bool _ddc_fastforward = true; #endif /* DEBUG_DUMP_COMMANDS */ diff --git a/src/network/network_func.h b/src/network/network_func.h index 66b4660169..4a31943e63 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -12,7 +12,7 @@ /** * Uncomment the following define to enable command replaying. - * See docs/desync.txt for details. + * See docs/desync.md for details. */ // #define DEBUG_DUMP_COMMANDS // #define DEBUG_FAILED_DUMP_COMMANDS From 83d99ec11d30cf4784eedeeeb088b4fb35b76555 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Apr 2024 21:38:11 +0100 Subject: [PATCH 014/107] Fix #12506: Update station/industry nearby lists in BuildOilRig (#12511) --- src/station_cmd.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index c1c81f893e..62ef3128b3 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -4336,6 +4336,19 @@ void BuildOilRig(TileIndex tile) st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE); st->UpdateVirtCoord(); + + /* An industry tile has now been replaced with a station tile, this may change the overlap between station catchments and industry tiles. + * Recalculate the station catchment for all stations currently in the industry's nearby list. + * Clear the industry's station nearby list first because Station::RecomputeCatchment cannot remove nearby industries in this case. */ + if (_settings_game.station.serve_neutral_industries) { + StationList nearby = std::move(st->industry->stations_near); + st->industry->stations_near.clear(); + for (Station *near : nearby) { + near->RecomputeCatchment(true); + UpdateStationAcceptance(near, true); + } + } + st->RecomputeCatchment(); UpdateStationAcceptance(st, false); } From 6458980413da684afb77f6b5157b323e657a54bf Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 Apr 2024 21:55:19 +0100 Subject: [PATCH 015/107] Change: Draw group hierarchy tree lines. (#12522) --- src/group_gui.cpp | 37 ++++++++++++++++++++++++++++++++----- src/group_gui.h | 5 +++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 40924c18d8..2fe19d2c50 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -118,7 +118,7 @@ static constexpr NWidgetPart _nested_group_widgets[] = { * @param parent Current tree parent (set by self with recursion). * @param indent Current tree indentation level (set by self with recursion). */ -static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent, int indent) +static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent = INVALID_GROUP, uint8_t indent = 0) { for (const auto &item : src) { if (item.group->parent != parent) continue; @@ -134,6 +134,16 @@ static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, GuiGroupListAddChildren(dst, src, fold, item.group->index, indent + 1); } } + + if (indent > 0 || dst.empty()) return; + + /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */ + uint16_t level_mask = 0; + for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) { + auto next_it = std::next(it); + SB(level_mask, it->indent, 1, it->indent <= next_it->indent); + next_it->level_mask = level_mask; + } } /** @@ -274,7 +284,7 @@ private: * @param protection Whether autoreplace protection is set. * @param has_children Whether the group has children and should have a fold / unfold button. */ - void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false, bool has_children = false) const + void DrawGroupInfo(int y, int left, int right, GroupID g_id, uint16_t level_mask = 0, uint8_t indent = 0, bool protection = false, bool has_children = false) const { /* Highlight the group if a vehicle is dragged over it */ if (g_id == this->group_over) { @@ -288,10 +298,27 @@ private: const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype); bool rtl = _current_text_dir == TD_RTL; + const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2; + const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent; + const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL); + + if (indent > 0) { + /* Draw tree continuation lines. */ + int tx = (rtl ? right - WidgetDimensions::scaled.framerect.right : left + WidgetDimensions::scaled.framerect.left) + offset; + for (uint lvl = 1; lvl <= indent; ++lvl) { + if (HasBit(level_mask, lvl)) GfxDrawLine(tx, y, tx, y + this->tiny_step_height - 1, linecolour, WidgetDimensions::scaled.fullbevel.top); + if (lvl < indent) tx += level_width; + } + /* Draw our node in the tree. */ + int ycentre = y + this->tiny_step_height / 2 - 1; + if (!HasBit(level_mask, indent)) GfxDrawLine(tx, y, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top); + GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top); + } + /* draw fold / unfold button */ int x = rtl ? right - WidgetDimensions::scaled.framerect.right - this->column_size[VGC_FOLD].width + 1 : left + WidgetDimensions::scaled.framerect.left; if (has_children) { - DrawSprite(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, rtl ? x - indent : x + indent, y + (this->tiny_step_height - this->column_size[VGC_FOLD].height) / 2); + DrawSprite(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, x + indent * level_width, y + (this->tiny_step_height - this->column_size[VGC_FOLD].height) / 2); } /* draw group name */ @@ -305,7 +332,7 @@ private: str = STR_GROUP_NAME; } x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_NAME].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_FOLD].width; - DrawString(x + (rtl ? 0 : indent), x + this->column_size[VGC_NAME].width - 1 - (rtl ? indent : 0), y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); + DrawString(x + (rtl ? 0 : indent * WidgetDimensions::scaled.hsep_indent), x + this->column_size[VGC_NAME].width - 1 - (rtl ? indent * WidgetDimensions::scaled.hsep_indent : 0), y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); /* draw autoreplace protection */ x = rtl ? x - WidgetDimensions::scaled.hsep_wide - this->column_size[VGC_PROTECT].width : x + WidgetDimensions::scaled.hsep_wide + this->column_size[VGC_NAME].width; @@ -624,7 +651,7 @@ public: assert(g->owner == this->owner); - DrawGroupInfo(y1, r.left, r.right, g->index, it->indent * WidgetDimensions::scaled.hsep_indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)); + DrawGroupInfo(y1, r.left, r.right, g->index, it->level_mask, it->indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)); y1 += this->tiny_step_height; } diff --git a/src/group_gui.h b/src/group_gui.h index ec5f790d84..d2fb2f71a0 100644 --- a/src/group_gui.h +++ b/src/group_gui.h @@ -19,9 +19,10 @@ void DeleteGroupHighlightOfVehicle(const Vehicle *v); struct GUIGroupListItem { const Group *group; - int8_t indent; ///< Display indentation level. + uint8_t indent; ///< Display indentation level. + uint16_t level_mask; ///< Bitmask of indentation continuation. - constexpr GUIGroupListItem(const Group *group, int8_t indent) : group(group), indent(indent) {} + constexpr GUIGroupListItem(const Group *group, int8_t indent) : group(group), indent(indent), level_mask(0) {} }; using GUIGroupList = GUIList; From 5a523cf212f24677dea0630f4119c8b8e2369d80 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 00:04:45 +0100 Subject: [PATCH 016/107] Codechange: Simplify FioCreateDirectory. `std::filesystem` provides `create_directories()` as a cross-platform way to create a directory tree. --- src/fileio.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 79f16392ab..bcd8a530e0 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -348,24 +348,9 @@ FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory s */ void FioCreateDirectory(const std::string &name) { - auto p = name.find_last_of(PATHSEPCHAR); - if (p != std::string::npos) { - std::string dirname = name.substr(0, p); - DIR *dir = ttd_opendir(dirname.c_str()); - if (dir == nullptr) { - FioCreateDirectory(dirname); // Try creating the parent directory, if we couldn't open it - } else { - closedir(dir); - } - } - - /* Ignore directory creation errors; they'll surface later on, and most - * of the time they are 'directory already exists' errors anyhow. */ -#if defined(_WIN32) - CreateDirectory(OTTD2FS(name).c_str(), nullptr); -#else - mkdir(OTTD2FS(name).c_str(), 0755); -#endif + /* Ignore directory creation errors; they'll surface later on. */ + std::error_code error_code; + std::filesystem::create_directories(OTTD2FS(name), error_code); } /** From d7c547d0db4276e412e18e5610f0d45ae9a2859c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 00:04:46 +0100 Subject: [PATCH 017/107] Codechange: Use directory_iterator to list directories in file list windows. This replaces use of custom ttd_opendir. Files are listed separately using ScanPath as that handles downloaded content. --- src/fileio.cpp | 2 -- src/fios.cpp | 63 +++++++++++++++++----------------------- src/os/unix/unix.cpp | 13 ++------- src/os/windows/win32.cpp | 22 ++++---------- 4 files changed, 33 insertions(+), 67 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index bcd8a530e0..285d7e471f 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -70,8 +70,6 @@ TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links -extern bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb); - /** * Checks whether the given search path is a valid search path * @param sp the search path to check diff --git a/src/fios.cpp b/src/fios.cpp index 91f622f058..dd98cb6699 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -33,8 +33,7 @@ SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix .c) */ extern bool FiosIsRoot(const std::string &path); -extern bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb); -extern bool FiosIsHiddenFile(const struct dirent *ent); +extern bool FiosIsHiddenFile(const std::filesystem::path &path); extern void FiosGetDrives(FileList &file_list); /* get the name of an oldstyle savegame */ @@ -322,48 +321,38 @@ bool FiosFileScanner::AddFile(const std::string &filename, size_t, const std::st */ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAndNameProc *callback_proc, Subdirectory subdir, FileList &file_list) { - struct stat sb; - struct dirent *dirent; - DIR *dir; - FiosItem *fios; size_t sort_start; file_list.clear(); assert(_fios_path != nullptr); - /* A parent directory link exists if we are not in the root directory */ - if (show_dirs && !FiosIsRoot(*_fios_path)) { - fios = &file_list.emplace_back(); - fios->type = FIOS_TYPE_PARENT; - fios->mtime = 0; - fios->name = ".."; - SetDParamStr(0, ".."); - fios->title = GetString(STR_SAVELOAD_PARENT_DIRECTORY); - } - - /* Show subdirectories */ - if (show_dirs && (dir = ttd_opendir(_fios_path->c_str())) != nullptr) { - while ((dirent = readdir(dir)) != nullptr) { - std::string d_name = FS2OTTD(dirent->d_name); - - /* found file must be directory, but not '.' or '..' */ - if (FiosIsValidFile(*_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && - (!FiosIsHiddenFile(dirent) || StrStartsWithIgnoreCase(PERSONAL_DIR, d_name)) && - d_name != "." && d_name != "..") { - fios = &file_list.emplace_back(); - fios->type = FIOS_TYPE_DIR; - fios->mtime = 0; - fios->name = d_name; - SetDParamStr(0, fios->name + PATHSEP); - fios->title = GetString(STR_SAVELOAD_DIRECTORY); - } - } - closedir(dir); - } - - /* Sort the subdirs always by name, ascending, remember user-sorting order */ if (show_dirs) { + /* A parent directory link exists if we are not in the root directory */ + if (!FiosIsRoot(*_fios_path)) { + FiosItem &fios = file_list.emplace_back(); + fios.type = FIOS_TYPE_PARENT; + fios.mtime = 0; + fios.name = ".."; + SetDParamStr(0, ".."); + fios.title = GetString(STR_SAVELOAD_PARENT_DIRECTORY); + } + + /* Show subdirectories */ + std::error_code error_code; + for (const auto &dir_entry : std::filesystem::directory_iterator(OTTD2FS(*_fios_path), error_code)) { + if (!dir_entry.is_directory()) continue; + if (FiosIsHiddenFile(dir_entry) && dir_entry.path().filename() != PERSONAL_DIR) continue; + + FiosItem &fios = file_list.emplace_back(); + fios.type = FIOS_TYPE_DIR; + fios.mtime = 0; + fios.name = FS2OTTD(dir_entry.path().filename()); + SetDParamStr(0, fios.name + PATHSEP); + fios.title = GetString(STR_SAVELOAD_DIRECTORY); + } + + /* Sort the subdirs always by name, ascending, remember user-sorting order */ SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; std::sort(file_list.begin(), file_list.end()); diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 2583be3347..b406cbc007 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -78,18 +78,9 @@ std::optional FiosGetDiskFreeSpace(const std::string &path) return std::nullopt; } -bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb) +bool FiosIsHiddenFile(const std::filesystem::path &path) { - assert(path.back() == PATHSEPCHAR); - if (path.size() > 2) assert(path[path.size() - 2] != PATHSEPCHAR); - std::string filename = fmt::format("{}{}", path, ent->d_name); - - return stat(filename.c_str(), sb) == 0; -} - -bool FiosIsHiddenFile(const struct dirent *ent) -{ - return ent->d_name[0] == '.'; + return path.filename().string().starts_with("."); } #ifdef WITH_ICONV diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 18655c3d42..b956027d52 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -192,27 +192,15 @@ void FiosGetDrives(FileList &file_list) } } -bool FiosIsValidFile(const std::string &, const struct dirent *ent, struct stat *sb) +bool FiosIsHiddenFile(const std::filesystem::path &path) { - /* hectonanoseconds between Windows and POSIX epoch */ - static const int64_t posix_epoch_hns = 0x019DB1DED53E8000LL; - const WIN32_FIND_DATA *fd = &ent->dir->fd; + UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // Disable 'no-disk' message box. - sb->st_size = ((uint64_t) fd->nFileSizeHigh << 32) + fd->nFileSizeLow; - /* UTC FILETIME to seconds-since-1970 UTC - * we just have to subtract POSIX epoch and scale down to units of seconds. - * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1� - * XXX - not entirely correct, since filetimes on FAT aren't UTC but local, - * this won't entirely be correct, but we use the time only for comparison. */ - sb->st_mtime = (time_t)((*(const uint64_t*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7); - sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG; + DWORD attributes = GetFileAttributes(path.c_str()); - return true; -} + SetErrorMode(sem); // Restore previous setting. -bool FiosIsHiddenFile(const struct dirent *ent) -{ - return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; + return (attributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; } std::optional FiosGetDiskFreeSpace(const std::string &path) From 42523379d983a693f8a358f79229951563057997 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 00:04:46 +0100 Subject: [PATCH 018/107] Codechange: Use directory_iterator in ScanPath. Replaces use of custom ttd_opendir. --- src/fileio.cpp | 58 +++++++++++++++++++---------------------------- src/fileio_func.h | 4 ++-- src/fios.cpp | 4 ++-- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 285d7e471f..803baa60f2 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1134,12 +1134,13 @@ std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, * @param filename The filename to look in for the extension. * @return True iff the extension is nullptr, or the filename ends with it. */ -static bool MatchesExtension(const char *extension, const char *filename) +static bool MatchesExtension(std::string_view extension, const std::string &filename) { - if (extension == nullptr) return true; + if (extension.empty()) return true; + if (filename.length() < extension.length()) return false; - const char *ext = strrchr(filename, extension[0]); - return ext != nullptr && StrEqualsIgnoreCase(ext, extension); + std::string_view filename_sv = filename; // String view to avoid making another copy of the substring. + return StrCompareIgnoreCase(extension, filename_sv.substr(filename_sv.length() - extension.length())) == 0; } /** @@ -1151,36 +1152,24 @@ static bool MatchesExtension(const char *extension, const char *filename) * @param basepath_length from where in the path are we 'based' on the search path * @param recursive whether to recursively search the sub directories */ -static uint ScanPath(FileScanner *fs, const char *extension, const char *path, size_t basepath_length, bool recursive) +static uint ScanPath(FileScanner *fs, std::string_view extension, const std::filesystem::path &path, size_t basepath_length, bool recursive) { uint num = 0; - struct stat sb; - struct dirent *dirent; - DIR *dir; - if (path == nullptr || (dir = ttd_opendir(path)) == nullptr) return 0; - - while ((dirent = readdir(dir)) != nullptr) { - std::string d_name = FS2OTTD(dirent->d_name); - - if (!FiosIsValidFile(path, dirent, &sb)) continue; - - std::string filename(path); - filename += d_name; - - if (S_ISDIR(sb.st_mode)) { - /* Directory */ + std::error_code error_code; + for (const auto &dir_entry : std::filesystem::directory_iterator(path, error_code)) { + if (dir_entry.is_directory()) { if (!recursive) continue; - if (d_name == "." || d_name == "..") continue; - AppendPathSeparator(filename); - num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); - } else if (S_ISREG(sb.st_mode)) { - /* File */ - if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, basepath_length, {})) num++; + num += ScanPath(fs, extension, dir_entry.path(), basepath_length, recursive); + } else if (dir_entry.is_regular_file()) { + std::string file = FS2OTTD(dir_entry.path()); + if (!MatchesExtension(extension, file)) continue; + if (fs->AddFile(file, basepath_length, {})) num++; } } - - closedir(dir); + if (error_code) { + Debug(misc, 9, "Unable to read directory {}: {}", path.string(), error_code.message()); + } return num; } @@ -1191,12 +1180,11 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s * @param extension the extension of files to search for. * @param tar the tar to search in. */ -static uint ScanTar(FileScanner *fs, const char *extension, const TarFileList::value_type &tar) +static uint ScanTar(FileScanner *fs, std::string_view extension, const TarFileList::value_type &tar) { uint num = 0; - const auto &filename = tar.first; - if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, 0, tar.second.tar_filename)) num++; + if (MatchesExtension(extension, tar.first) && fs->AddFile(tar.first, 0, tar.second.tar_filename)) num++; return num; } @@ -1210,7 +1198,7 @@ static uint ScanTar(FileScanner *fs, const char *extension, const TarFileList::v * @return the number of found files, i.e. the number of times that * AddFile returned true. */ -uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool recursive) +uint FileScanner::Scan(std::string_view extension, Subdirectory sd, bool tars, bool recursive) { this->subdir = sd; @@ -1221,7 +1209,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; std::string path = FioGetDirectory(sp, sd); - num += ScanPath(this, extension, path.c_str(), path.size(), recursive); + num += ScanPath(this, extension, OTTD2FS(path), path.size(), recursive); } if (tars && sd != NO_DIRECTORY) { @@ -1252,9 +1240,9 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r * @return the number of found files, i.e. the number of times that * AddFile returned true. */ -uint FileScanner::Scan(const char *extension, const std::string &directory, bool recursive) +uint FileScanner::Scan(const std::string_view extension, const std::string &directory, bool recursive) { std::string path(directory); AppendPathSeparator(path); - return ScanPath(this, extension, path.c_str(), path.size(), recursive); + return ScanPath(this, extension, OTTD2FS(path), path.size(), recursive); } diff --git a/src/fileio_func.h b/src/fileio_func.h index 2a13a454d4..9e85f1f8c0 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -42,8 +42,8 @@ public: /** Destruct the proper one... */ virtual ~FileScanner() = default; - uint Scan(const char *extension, Subdirectory sd, bool tars = true, bool recursive = true); - uint Scan(const char *extension, const std::string &directory, bool recursive = true); + uint Scan(std::string_view extension, Subdirectory sd, bool tars = true, bool recursive = true); + uint Scan(std::string_view extension, const std::string &directory, bool recursive = true); /** * Add a file with the given filename. diff --git a/src/fios.cpp b/src/fios.cpp index dd98cb6699..f5523c85aa 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -365,9 +365,9 @@ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAn /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); if (subdir == NO_DIRECTORY) { - scanner.Scan(nullptr, *_fios_path, false); + scanner.Scan({}, *_fios_path, false); } else { - scanner.Scan(nullptr, subdir, true, true); + scanner.Scan({}, subdir, true, true); } std::sort(file_list.begin() + sort_start, file_list.end()); From 63ce81570ce2f6ed4be53ca73bd0fbf8c358088b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 00:04:47 +0100 Subject: [PATCH 019/107] Remove: Custom opendir implementation for Windows no longer needed. std::filesystem::directory_iterator is now used instead. --- src/fileio_func.h | 34 ------------ src/os/windows/win32.cpp | 112 --------------------------------------- 2 files changed, 146 deletions(-) diff --git a/src/fileio_func.h b/src/fileio_func.h index 9e85f1f8c0..eaa6f76164 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -81,40 +81,6 @@ public: DECLARE_ENUM_AS_BIT_SET(TarScanner::Mode) -/* Implementation of opendir/readdir/closedir for Windows */ -#if defined(_WIN32) -struct DIR; - -struct dirent { // XXX - only d_name implemented - wchar_t *d_name; // name of found file - /* little hack which will point to parent DIR struct which will - * save us a call to GetFileAttributes if we want information - * about the file (for example in function fio_bla) */ - DIR *dir; -}; - -DIR *opendir(const wchar_t *path); -struct dirent *readdir(DIR *d); -int closedir(DIR *d); -#else -/* Use system-supplied opendir/readdir/closedir functions */ -# include -# include -#endif /* defined(_WIN32) */ - -/** - * A wrapper around opendir() which will convert the string from - * OPENTTD encoding to that of the filesystem. For all purposes this - * function behaves the same as the original opendir function - * @param path string to open directory of - * @return DIR pointer - */ -inline DIR *ttd_opendir(const char *path) -{ - return opendir(OTTD2FS(path).c_str()); -} - - /** Auto-close a file upon scope exit. */ class FileCloser { FILE *f; diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index b956027d52..c011e830f6 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -58,118 +58,6 @@ void OSOpenBrowser(const std::string &url) ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } -/* Code below for windows version of opendir/readdir/closedir copied and - * modified from Jan Wassenberg's GPL implementation posted over at - * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1� */ - -struct DIR { - HANDLE hFind; - /* the dirent returned by readdir. - * note: having only one global instance is not possible because - * multiple independent opendir/readdir sequences must be supported. */ - dirent ent; - WIN32_FIND_DATA fd; - /* since opendir calls FindFirstFile, we need a means of telling the - * first call to readdir that we already have a file. - * that's the case iff this is true */ - bool at_first_entry; -}; - -/* suballocator - satisfies most requests with a reusable static instance. - * this avoids hundreds of alloc/free which would fragment the heap. - * To guarantee concurrency, we fall back to malloc if the instance is - * already in use (it's important to avoid surprises since this is such a - * low-level routine). */ -static DIR _global_dir; -static LONG _global_dir_is_in_use = false; - -static inline DIR *dir_calloc() -{ - DIR *d; - - if (InterlockedExchange(&_global_dir_is_in_use, true) == (LONG)true) { - d = CallocT(1); - } else { - d = &_global_dir; - memset(d, 0, sizeof(*d)); - } - return d; -} - -static inline void dir_free(DIR *d) -{ - if (d == &_global_dir) { - _global_dir_is_in_use = (LONG)false; - } else { - free(d); - } -} - -DIR *opendir(const wchar_t *path) -{ - DIR *d; - UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box - DWORD fa = GetFileAttributes(path); - - if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { - d = dir_calloc(); - if (d != nullptr) { - std::wstring search_path = path; - bool slash = path[wcslen(path) - 1] == '\\'; - - /* build search path for FindFirstFile, try not to append additional slashes - * as it throws Win9x off its groove for root directories */ - if (!slash) search_path += L"\\"; - search_path += L"*"; - d->hFind = FindFirstFile(search_path.c_str(), &d->fd); - - if (d->hFind != INVALID_HANDLE_VALUE || - GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty - d->ent.dir = d; - d->at_first_entry = true; - } else { - dir_free(d); - d = nullptr; - } - } else { - errno = ENOMEM; - } - } else { - /* path not found or not a directory */ - d = nullptr; - errno = ENOENT; - } - - SetErrorMode(sem); // restore previous setting - return d; -} - -struct dirent *readdir(DIR *d) -{ - DWORD prev_err = GetLastError(); // avoid polluting last error - - if (d->at_first_entry) { - /* the directory was empty when opened */ - if (d->hFind == INVALID_HANDLE_VALUE) return nullptr; - d->at_first_entry = false; - } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail - if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); - return nullptr; - } - - /* This entry has passed all checks; return information about it. - * (note: d_name is a pointer; see struct dirent definition) */ - d->ent.d_name = d->fd.cFileName; - return &d->ent; -} - -int closedir(DIR *d) -{ - FindClose(d->hFind); - dir_free(d); - return 0; -} - bool FiosIsRoot(const std::string &file) { return file.size() == 3; // C:\... From c355e98c5899a12648e38e7fdeebbdfd2621ef52 Mon Sep 17 00:00:00 2001 From: translators Date: Thu, 18 Apr 2024 04:40:27 +0000 Subject: [PATCH 020/107] Update: Translations from eints english (au): 4 changes by krysclarke russian: 4 changes by Ln-Wolf finnish: 7 changes by hpiirai portuguese: 4 changes by azulcosta portuguese (brazilian): 5 changes by pasantoro polish: 4 changes by pAter-exe --- src/lang/brazilian_portuguese.txt | 6 +++++- src/lang/english_AU.txt | 4 ++++ src/lang/finnish.txt | 10 +++++++--- src/lang/polish.txt | 4 ++++ src/lang/portuguese.txt | 4 ++++ src/lang/russian.txt | 4 ++++ 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 860a5f0184..be2b27f66b 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -5282,11 +5282,15 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... veí STR_ERROR_CAN_T_CLONE_VEHICLE_LIST :{WHITE}... nem todos os veículos são idênticos -STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Não haverá veículos disponíveis +STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Nenhum veículo estará disponível STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Modifique a sua configuração de NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Não existem veículos disponíveis ainda STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Inicie um novo jogo depois de {DATE_SHORT} ou utilize um NewGRF que forneça veículos iniciais +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}Nenhum tipo de estrada urbana está disponível +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Modifique a sua configuração de NewGRF +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}Não existem tipos de estrada urbana disponíveis ainda +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Inicie um novo jogo depois de {DATE_SHORT} ou utilize um NewGRF que forneça estradas urbanas iniciais # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Não é possível fazer o trem passar o sinal em perigo... diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index f432d6d71b..e3782bcd19 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -5286,6 +5286,10 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change y STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF which provides early vehicles +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}No town-buildable road types are available +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change your NewGRF configuration +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}No town-buildable road types are available yet +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early town-buildable road types # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 017948e152..14a5098396 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -1311,7 +1311,7 @@ STR_CONFIG_SETTING_RECESSIONS :Lamat: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Mikäli käytössä, taloudellinen lama voi ilmaantua ajoittain. Laman aikana kaikki tuotanto on huomattavasti alhaisempaa (palautuu normaalille tasolle laman päätyttyä) STR_CONFIG_SETTING_TRAIN_REVERSING :Estä junien kääntyminen asemilla: {STRING} -STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Mikäli käytössä, junat eivät käänny läpiajettavilla asemilla vaikka kääntymisen jälkeen saatavilla olisi lyhempi reitti +STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Mikäli käytössä, junat eivät käänny läpiajettavilla asemilla vaikka kääntymisen jälkeen tarjolla olisi lyhempi reitti STR_CONFIG_SETTING_DISASTERS :Onnettomuudet: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Ottaa käyttöön onnettomuudet jotka saattavat ajoittain estää tai tuhota liikennettä tai infrastruktuuria @@ -5281,11 +5281,15 @@ STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... kulk STR_ERROR_CAN_T_CLONE_VEHICLE_LIST :{WHITE}… kaikki kulkuneuvot eivät ole identtisiä -STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Yhtään kulkuneuvoa ei ole saatavilla +STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Yhtään kulkuneuvoa ei ole käytettävissä STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Muuta NewGRF-asetuksiasi STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Kulkuneuvoja ei ole vielä saatavilla -STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Aloita peli {DATE_SHORT} jälkeen tai käytä NewGRF:ää joka tarjoaa aikaisempia kulkuneuvoja +STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Aloita uusi peli {DATE_SHORT} jälkeen tai käytä NewGRF:ää, joka tarjoaa varhaisia kulkuneuvoja +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}Yhtään kunnan rakennettavissa olevaa tietyyppiä ei ole käytettävissä +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Muuta NewGRF-asetuksia +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}Kunnan rakennettavissa olevia tietyyppejä ei ole vielä saatavilla +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Aloita uusi peli {DATE_SHORT} jälkeen tai käytä NewGRF:ää, joka tarjoaa varhaisia kunnan rakennettavissa olevia tietyyppejä # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Junaa ei voi pakottaa jatkamaan punaisen opastimen ohi... diff --git a/src/lang/polish.txt b/src/lang/polish.txt index ae307a167f..ee5ab860d3 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -5672,6 +5672,10 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zmień k STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Obecnie żaden pojazd nie jest dostępny STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Zacznij grę po {DATE_SHORT} albo użyj zestawu NewGRF, który zawiera wczesne pojazdy +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}Brak dostępnych typów dróg miejskich +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Zmień konfigurację NewGRF +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}Brak jeszcze dostępnych typów dróg miejskich +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Rozpocznij nową grę po {DATE_SHORT} roku lub użyj NewGRF, który umożliwia wczesne budowanie dróg miejskich # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nie można przepuścić pociągu za sygnał, niebezpieczeństwo... diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 6c7e8b5904..74c418193a 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -5287,6 +5287,10 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Mudar a STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nenhum veículo ainda disponível STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Começar um novo jogo depois de {DATE_SHORT} ou utilizar um NewGRF que forneça veículos iniciais +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}Não está disponível nenhum tipo de estrada edificável para localidades +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Mudar a sua configuração NewGRF +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}Ainda não estão disponíveis tipos de estradas edificáveis para localidades +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Começar um novo jogo depois de {DATE_SHORT} ou usar um NewGRF que forneça antecipadamente tipos de estradas edificáveis em localidades # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Não é possível fazer o comboio passar o sinal com perigo... diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 598bb83968..5fbcbcba24 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -5473,6 +5473,10 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Изме STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Нет доступных транспортных средств STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Начните игру не ранее {DATE_SHORT} либо подключите NewGRF, добавляющий транспортные средства, использовавшиеся в это время. +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL :{WHITE}Отсутствуют типы дорог, которые могла бы прокладывать городская администрация +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Измените конфигурацию установленных модулей NewGRF +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET :{WHITE}Пока что отсутствуют типы дорог, которые могла бы прокладывать городская администрация +STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION :{WHITE}Установите дату начала игры не ранее {DATE_SHORT} или установите модуль NewGRF, добавляющий типы дорог, которые будут доступны администрациям городов на выбранную вами дату # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Невозможно игнорировать светофор. Опасно... From 715f8c0218b10700a9d41c2ad54c8b0f1776e4f3 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 18 Apr 2024 18:41:36 +0200 Subject: [PATCH 021/107] Codefix: cast to "CommandCallback *" in a way cast-function-type-mismatch doesn't mind (#12529) --- src/command_func.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command_func.h b/src/command_func.h index ddf68aaf11..69cb9ebcac 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -250,7 +250,7 @@ public: template static Tret Unsafe(StringID err_message, Tcallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple args) { - return Execute(err_message, reinterpret_cast(callback), my_cmd, estimate_only, false, location, std::move(args)); + return Execute(err_message, reinterpret_cast(reinterpret_cast(callback)), my_cmd, estimate_only, false, location, std::move(args)); } protected: @@ -301,7 +301,7 @@ protected: /* Only set client IDs when the command does not come from the network. */ if (!network_command && GetCommandFlags() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for{}); - Tret res = Execute(err_message, reinterpret_cast(callback), my_cmd, estimate_only, network_command, tile, args); + Tret res = Execute(err_message, reinterpret_cast(reinterpret_cast(callback)), my_cmd, estimate_only, network_command, tile, args); InternalPostResult(ExtractCommandCost(res), tile, estimate_only, only_sending, err_message, my_cmd); if (!estimate_only && !only_sending && callback != nullptr) { From 78b83190ccf71b85b7d087aaa95aba1166dfc3c9 Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Thu, 18 Apr 2024 12:45:00 -0400 Subject: [PATCH 022/107] Fix: Mark vehicle status bars dirty when a vehicle leaves unbunching depot (#12516) --- src/vehicle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 12941e7e83..2e1b82b172 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2545,6 +2545,7 @@ void Vehicle::LeaveUnbunchingDepot() if (u->vehstatus & (VS_STOPPED | VS_CRASHED)) continue; u->depot_unbunching_next_departure = next_departure; + SetWindowDirty(WC_VEHICLE_VIEW, u->index); } } From 4170c9923a64868098c03d7d45477d088786d83e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 17:45:41 +0100 Subject: [PATCH 023/107] Fix: Inconsistent space between console history and current line. (#12528) --- src/console_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 6dc0393e66..496d945934 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -196,7 +196,7 @@ struct IConsoleWindow : Window const int right = this->width - WidgetDimensions::scaled.frametext.right; GfxFillRect(0, 0, this->width - 1, this->height - 1, PC_BLACK); - int ypos = this->height - this->line_height; + int ypos = this->height - this->line_height - WidgetDimensions::scaled.hsep_normal; for (size_t line_index = IConsoleWindow::scroll; line_index < _iconsole_buffer.size(); line_index++) { const IConsoleLine &print = _iconsole_buffer[line_index]; SetDParamStr(0, print.buffer); From 08d05bf4c0530f00d0b46312436781be40f3ae3e Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 18 Apr 2024 19:12:52 +0200 Subject: [PATCH 024/107] Doc: update release documentation with the latest (#12525) --- docs/releasing_openttd.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/releasing_openttd.md b/docs/releasing_openttd.md index acb3ad9bc7..08c379dd81 100644 --- a/docs/releasing_openttd.md +++ b/docs/releasing_openttd.md @@ -29,20 +29,25 @@ This guide is for OpenTTD developers/maintainers, to release a new version of Op 1. Go to https://github.com/OpenTTD/website/new/main/_posts and write a new announcement post. See a [previous example](https://github.com/OpenTTD/website/pull/238) for a template. 2. Create a new branch for this post and open a PR for it. -3. Write announcement text for socials like Forum/Discord/Twitter/Reddit and include it in the PR. +3. Write announcement text for the store pages and socials like TT-Forums / Discord / Twitter / Reddit / Fosstodon / etc., and include it in the PR. 4. Create a Steam news image for that post and include it in the PR. -5. Check the website post (preview link via checks page) and make corrections. We usually just use the GitHub web interface for this and squash the result later. +5. Check the website post ("View Deployment" link) and make corrections. We usually just use the GitHub web interface for this and squash the result later. 6. Get this PR approved, but do not merge yet. ## Step 3: Make the actual OpenTTD release -1. Go to https://github.com/OpenTTD/OpenTTD/releases/new and create a new tag matching the release number. For the body of the release, see any older release. "Set as a pre-release" for a beta or RC, set as latest for a real release. -2. Merge website PR. -3. Wait for the OpenTTD release checks to be complete. -4. Check that website links to the new release are working and correct, using the [staging website](https://www-staging.openttd.org/). -5. If this is a full release, ask orudge to update the Microsoft Store and TrueBrain to move the release from the "testing" to "default" branch on Steam. +1. Go to https://github.com/OpenTTD/OpenTTD/releases/new and create a new tag matching the release number. For the body of the release, copy in the changelog. "Set as a pre-release" for a beta or RC. +2. Wait for the OpenTTD release workflow to be complete. +3. Merge the website PR. This will publish the release post. +4. If this is a full release: + * for `Steam`: under Steamworks -> SteamPipe -> Builds, set the "testing" branch live on the "default" branch. This will request 2FA validation. + * for `GOG`: under Builds, "Publish" the freshly uploaded builds to `Master`, `GOG-use only` and `Testing`. + * for `Microsoft Store`: ask orudge to publish the new release. + +Access to `Steam`, `GOG` and/or `Microsoft Store` requires a developer account on that platform. +You will need access to the shared keystore in order to create such an account. +For help and/or access to either or both, please contact TrueBrain. ## Step 4: Tell the world -1. Tag and create a website release to trigger the actions that update the website. -2. After the website is live, make announcements on social media. You may need to coordinate with other developers who can make posts on Twitter, Reddit, Steam, and GOG. +1. Make announcements on social media and store pages. You may need to coordinate with other developers who can make posts on TT-Forums, Twitter, Reddit, Fosstodon, Discord, Steam, GOG, Microsoft Store, etc. From 04a3bf76e840cdf4b1dc79479b62b4d626c4bee1 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 18 Apr 2024 19:37:33 +0200 Subject: [PATCH 025/107] Codechange: upgrade Emscripten to 3.1.57 (#12526) This also upgrades liblzma to 5.4.6, and uses the new ports.contrib system Emscripten 3.1.56 introduced. --- .github/workflows/ci-emscripten.yml | 9 +- .github/workflows/preview-build.yml | 9 +- os/emscripten/Dockerfile | 5 +- os/emscripten/README.md | 4 +- os/emscripten/cmake/FindLibLZMA.cmake | 8 +- os/emscripten/emsdk-liblzma.patch | 198 -------------------------- os/emscripten/ports/liblzma.py | 139 ++++++++++++++++++ 7 files changed, 155 insertions(+), 217 deletions(-) delete mode 100644 os/emscripten/emsdk-liblzma.patch create mode 100644 os/emscripten/ports/liblzma.py diff --git a/.github/workflows/ci-emscripten.yml b/.github/workflows/ci-emscripten.yml index e1814ed79b..8c50713b9e 100644 --- a/.github/workflows/ci-emscripten.yml +++ b/.github/workflows/ci-emscripten.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 container: # If you change this version, change the number in the cache step too. - image: emscripten/emsdk:3.1.42 + image: emscripten/emsdk:3.1.57 steps: - name: Checkout @@ -23,12 +23,11 @@ jobs: uses: actions/cache@v4 with: path: /emsdk/upstream/emscripten/cache - key: 3.1.42-${{ runner.os }} + key: 3.1.57-${{ runner.os }} - - name: Patch Emscripten to support LZMA + - name: Add liblzma support run: | - cd /emsdk/upstream/emscripten - patch -p1 < ${GITHUB_WORKSPACE}/os/emscripten/emsdk-liblzma.patch + cp ${GITHUB_WORKSPACE}/os/emscripten/ports/liblzma.py /emsdk/upstream/emscripten/tools/ports/contrib/ - name: Build (host tools) run: | diff --git a/.github/workflows/preview-build.yml b/.github/workflows/preview-build.yml index 0bb79ed4b9..9cf6e9573c 100644 --- a/.github/workflows/preview-build.yml +++ b/.github/workflows/preview-build.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest container: # If you change this version, change the number in the cache step too. - image: emscripten/emsdk:3.1.42 + image: emscripten/emsdk:3.1.57 steps: - name: Checkout @@ -38,12 +38,11 @@ jobs: uses: actions/cache@v4 with: path: /emsdk/upstream/emscripten/cache - key: 3.1.42-${{ runner.os }} + key: 3.1.57-${{ runner.os }} - - name: Patch Emscripten to support LZMA + - name: Add liblzma support run: | - cd /emsdk/upstream/emscripten - patch -p1 < ${GITHUB_WORKSPACE}/os/emscripten/emsdk-liblzma.patch + cp ${GITHUB_WORKSPACE}/os/emscripten/ports/liblzma.py /emsdk/upstream/emscripten/tools/ports/contrib/ - name: Build (host tools) run: | diff --git a/os/emscripten/Dockerfile b/os/emscripten/Dockerfile index 178f56500b..543bf6b2de 100644 --- a/os/emscripten/Dockerfile +++ b/os/emscripten/Dockerfile @@ -1,4 +1,3 @@ -FROM emscripten/emsdk:3.1.42 +FROM emscripten/emsdk:3.1.57 -COPY emsdk-liblzma.patch / -RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-liblzma.patch +COPY ports/liblzma.py /emsdk/upstream/emscripten/tools/ports/contrib/liblzma.py diff --git a/os/emscripten/README.md b/os/emscripten/README.md index 9184b0144e..cdc038ade3 100644 --- a/os/emscripten/README.md +++ b/os/emscripten/README.md @@ -2,8 +2,8 @@ Please use docker with the supplied `Dockerfile` to build for emscripten. It takes care of a few things: -- Use a version of emscripten we know works -- Patch in LibLZMA support (as this is not supported by upstream) +- Use a version of emscripten we know works. +- Add LibLZMA library under contrib ports. First, build the docker image by navigating in the folder this `README.md` is in, and executing: ``` diff --git a/os/emscripten/cmake/FindLibLZMA.cmake b/os/emscripten/cmake/FindLibLZMA.cmake index cd6b44ad3d..0880d62f70 100644 --- a/os/emscripten/cmake/FindLibLZMA.cmake +++ b/os/emscripten/cmake/FindLibLZMA.cmake @@ -1,7 +1,7 @@ # LibLZMA is a custom addition to the emscripten SDK, so it is possible # someone patched their SDK. Test out if the SDK supports LibLZMA. include(CheckCXXSourceCompiles) -set(CMAKE_REQUIRED_FLAGS "-sUSE_LIBLZMA=1") +set(CMAKE_REQUIRED_FLAGS "--use-port=contrib.liblzma") check_cxx_source_compiles(" #include @@ -12,9 +12,9 @@ check_cxx_source_compiles(" if (LIBLZMA_FOUND) add_library(LibLZMA::LibLZMA INTERFACE IMPORTED) set_target_properties(LibLZMA::LibLZMA PROPERTIES - INTERFACE_COMPILE_OPTIONS "-sUSE_LIBLZMA=1" - INTERFACE_LINK_LIBRARIES "-sUSE_LIBLZMA=1" + INTERFACE_COMPILE_OPTIONS "--use-port=contrib.liblzma" + INTERFACE_LINK_LIBRARIES "--use-port=contrib.liblzma" ) else() - message(WARNING "You are using an emscripten SDK without LibLZMA support. Many savegames won't be able to load in OpenTTD. Please apply 'emsdk-liblzma.patch' to your local emsdk installation.") + message(WARNING "You are using an emscripten SDK without LibLZMA support. Many savegames won't be able to load in OpenTTD. Please copy liblzma.py to your ports/contrib folder in your local emsdk installation.") endif() diff --git a/os/emscripten/emsdk-liblzma.patch b/os/emscripten/emsdk-liblzma.patch deleted file mode 100644 index 7bfdd47de2..0000000000 --- a/os/emscripten/emsdk-liblzma.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 84d0e9112d5c87a714abd21ec8547921f46f37b5 Mon Sep 17 00:00:00 2001 -From: milek7 -Date: Tue, 8 Dec 2020 01:03:31 +0100 -Subject: [PATCH] Add liblzma port - ---- - src/settings.js | 4 ++ - tools/ports/liblzma.py | 151 +++++++++++++++++++++++++++++++++++++++++ - tools/settings.py | 1 + - 3 files changed, 156 insertions(+) - create mode 100644 tools/ports/liblzma.py - -diff --git a/src/settings.js b/src/settings.js -index f93140d..7b6bec9 100644 ---- a/src/settings.js -+++ b/src/settings.js -@@ -1451,6 +1451,10 @@ var USE_GIFLIB = false; - // [compile+link] - var USE_LIBJPEG = false; - -+// 1 = use liblzma from emscripten-ports -+// [compile+link] -+var USE_LIBLZMA = false; -+ - // 1 = use libpng from emscripten-ports - // [compile+link] - var USE_LIBPNG = false; -diff --git a/tools/ports/liblzma.py b/tools/ports/liblzma.py -new file mode 100644 -index 0000000..6872a8b ---- /dev/null -+++ b/tools/ports/liblzma.py -@@ -0,0 +1,151 @@ -+# Copyright 2020 The Emscripten Authors. All rights reserved. -+# Emscripten is available under two separate licenses, the MIT license and the -+# University of Illinois/NCSA Open Source License. Both these licenses can be -+# found in the LICENSE file. -+ -+import os -+import shutil -+import logging -+from pathlib import Path -+ -+VERSION = '5.4.2' -+HASH = '149f980338bea3d66de1ff5994b2b236ae1773135eda68b62b009df0c9dcdf5467f8cb2c06da95a71b6556d60bd3d21f475feced34d5dfdb80ee95416a2f9737' -+ -+ -+def needed(settings): -+ return settings.USE_LIBLZMA -+ -+ -+def get(ports, settings, shared): -+ ports.fetch_project('liblzma', f'https://tukaani.org/xz/xz-{VERSION}.tar.gz', sha512hash=HASH) -+ -+ def create(final): -+ logging.info('building port: liblzma') -+ -+ ports.clear_project_build('liblzma') -+ -+ source_path = os.path.join(ports.get_dir(), 'liblzma', f'xz-{VERSION}', 'src', 'liblzma') -+ ports.write_file(os.path.join(source_path, 'config.h'), config_h) -+ ports.install_headers(os.path.join(source_path, 'api'), pattern='lzma.h') -+ ports.install_headers(os.path.join(source_path, 'api', 'lzma'), pattern='*.h', target='lzma') -+ -+ build_flags = ['-DHAVE_CONFIG_H', '-DTUKLIB_SYMBOL_PREFIX=lzma_', '-fvisibility=hidden'] -+ exclude_files = ['crc32_small.c', 'crc64_small.c', 'crc32_tablegen.c', 'crc64_tablegen.c', 'price_tablegen.c', 'fastpos_tablegen.c', -+ 'tuklib_exit.c', 'tuklib_mbstr_fw.c', 'tuklib_mbstr_width.c', 'tuklib_open_stdxxx.c', 'tuklib_progname.c'] -+ include_dirs_rel = ['../common', 'api', 'check', 'common', 'delta', 'lz', 'lzma', 'rangecoder', 'simple'] -+ -+ include_dirs = [os.path.join(source_path, p) for p in include_dirs_rel] -+ ports.build_port(source_path, final, 'liblzma', flags=build_flags, exclude_files=exclude_files, includes=include_dirs) -+ -+ return [shared.cache.get_lib('liblzma.a', create, what='port')] -+ -+ -+def clear(ports, settings, shared): -+ shared.cache.erase_lib('liblzma.a') -+ -+ -+def process_args(ports): -+ return [] -+ -+ -+def show(): -+ return 'liblzma (USE_LIBLZMA=1; public domain)' -+ -+ -+config_h = ''' -+#define ASSUME_RAM 128 -+#define ENABLE_NLS 1 -+#define HAVE_CHECK_CRC32 1 -+#define HAVE_CHECK_CRC64 1 -+#define HAVE_CHECK_SHA256 1 -+#define HAVE_CLOCK_GETTIME 1 -+#define HAVE_DCGETTEXT 1 -+#define HAVE_DECL_CLOCK_MONOTONIC 1 -+#define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 -+#define HAVE_DECODERS 1 -+#define HAVE_DECODER_ARM 1 -+#define HAVE_DECODER_ARMTHUMB 1 -+#define HAVE_DECODER_DELTA 1 -+#define HAVE_DECODER_IA64 1 -+#define HAVE_DECODER_LZMA1 1 -+#define HAVE_DECODER_LZMA2 1 -+#define HAVE_DECODER_POWERPC 1 -+#define HAVE_DECODER_SPARC 1 -+#define HAVE_DECODER_X86 1 -+#define HAVE_DLFCN_H 1 -+#define HAVE_ENCODERS 1 -+#define HAVE_ENCODER_ARM 1 -+#define HAVE_ENCODER_ARMTHUMB 1 -+#define HAVE_ENCODER_DELTA 1 -+#define HAVE_ENCODER_IA64 1 -+#define HAVE_ENCODER_LZMA1 1 -+#define HAVE_ENCODER_LZMA2 1 -+#define HAVE_ENCODER_POWERPC 1 -+#define HAVE_ENCODER_SPARC 1 -+#define HAVE_ENCODER_X86 1 -+#define HAVE_FCNTL_H 1 -+#define HAVE_FUTIMENS 1 -+#define HAVE_GETOPT_H 1 -+#define HAVE_GETOPT_LONG 1 -+#define HAVE_GETTEXT 1 -+#define HAVE_IMMINTRIN_H 1 -+#define HAVE_INTTYPES_H 1 -+#define HAVE_LIMITS_H 1 -+#define HAVE_MBRTOWC 1 -+#define HAVE_MEMORY_H 1 -+#define HAVE_MF_BT2 1 -+#define HAVE_MF_BT3 1 -+#define HAVE_MF_BT4 1 -+#define HAVE_MF_HC3 1 -+#define HAVE_MF_HC4 1 -+#define HAVE_OPTRESET 1 -+#define HAVE_POSIX_FADVISE 1 -+#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1 -+#define HAVE_PTHREAD_PRIO_INHERIT 1 -+#define HAVE_STDBOOL_H 1 -+#define HAVE_STDINT_H 1 -+#define HAVE_STDLIB_H 1 -+#define HAVE_STRINGS_H 1 -+#define HAVE_STRING_H 1 -+#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1 -+#define HAVE_SYS_PARAM_H 1 -+#define HAVE_SYS_STAT_H 1 -+#define HAVE_SYS_TIME_H 1 -+#define HAVE_SYS_TYPES_H 1 -+#define HAVE_UINTPTR_T 1 -+#define HAVE_UNISTD_H 1 -+#define HAVE_VISIBILITY 1 -+#define HAVE_WCWIDTH 1 -+#define HAVE__BOOL 1 -+#define HAVE___BUILTIN_ASSUME_ALIGNED 1 -+#define HAVE___BUILTIN_BSWAPXX 1 -+#define MYTHREAD_POSIX 1 -+#define NDEBUG 1 -+#define PACKAGE "xz" -+#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org" -+#define PACKAGE_NAME "XZ Utils" -+#define PACKAGE_STRING "XZ Utils 5.4.0" -+#define PACKAGE_TARNAME "xz" -+#define PACKAGE_VERSION "5.4.0" -+#define SIZEOF_SIZE_T 4 -+#define STDC_HEADERS 1 -+#define TUKLIB_CPUCORES_SYSCONF 1 -+#define TUKLIB_FAST_UNALIGNED_ACCESS 1 -+#define TUKLIB_PHYSMEM_SYSCONF 1 -+#ifndef _ALL_SOURCE -+# define _ALL_SOURCE 1 -+#endif -+#ifndef _GNU_SOURCE -+# define _GNU_SOURCE 1 -+#endif -+#ifndef _POSIX_PTHREAD_SEMANTICS -+# define _POSIX_PTHREAD_SEMANTICS 1 -+#endif -+#ifndef _TANDEM_SOURCE -+# define _TANDEM_SOURCE 1 -+#endif -+#ifndef __EXTENSIONS__ -+# define __EXTENSIONS__ 1 -+#endif -+#define VERSION "5.4.0" -+''' -diff --git a/tools/settings.py b/tools/settings.py -index 10d6ca0..827e4a9 100644 ---- a/tools/settings.py -+++ b/tools/settings.py -@@ -40,6 +40,7 @@ PORTS_SETTINGS = { - 'USE_SDL_NET', - 'USE_SDL_GFX', - 'USE_LIBJPEG', -+ 'USE_LIBLZMA', - 'USE_OGG', - 'USE_REGAL', - 'USE_BOOST_HEADERS', --- -2.34.1 diff --git a/os/emscripten/ports/liblzma.py b/os/emscripten/ports/liblzma.py new file mode 100644 index 0000000000..0adf0e5697 --- /dev/null +++ b/os/emscripten/ports/liblzma.py @@ -0,0 +1,139 @@ +import os +import logging + +VERSION = '5.4.6' +HASH = '495cc890d25c075c927c907b77e60d86dd8a4c377cea5b1172c8e916984149a7bb5fb32db25091f7219346b83155b47e4bc0404cc8529d992014cd7ed0c278b7' + +URL = 'https://github.com/tukaani-project/xz' +DESCRIPTION = 'liblzma provides a general-purpose data-compression library.' +LICENSE = 'LGPL-2.1' + +def get(ports, settings, shared): + ports.fetch_project('contrib.liblzma', f'https://github.com/tukaani-project/xz/releases/download/v{VERSION}/xz-{VERSION}.tar.xz', sha512hash=HASH) + + def create(final): + logging.info('building port: contrib.liblzma') + + ports.clear_project_build('contrib.liblzma') + + source_path = os.path.join(ports.get_dir(), 'contrib.liblzma', f'xz-{VERSION}', 'src', 'liblzma') + ports.write_file(os.path.join(source_path, 'config.h'), config_h) + ports.install_headers(os.path.join(source_path, 'api'), pattern='lzma.h') + ports.install_headers(os.path.join(source_path, 'api', 'lzma'), pattern='*.h', target='lzma') + + build_flags = ['-DHAVE_CONFIG_H', '-DTUKLIB_SYMBOL_PREFIX=lzma_', '-fvisibility=hidden'] + exclude_files = ['crc32_small.c', 'crc64_small.c', 'crc32_tablegen.c', 'crc64_tablegen.c', 'price_tablegen.c', 'fastpos_tablegen.c', + 'tuklib_exit.c', 'tuklib_mbstr_fw.c', 'tuklib_mbstr_width.c', 'tuklib_open_stdxxx.c', 'tuklib_progname.c'] + include_dirs_rel = ['../common', 'api', 'check', 'common', 'delta', 'lz', 'lzma', 'rangecoder', 'simple'] + + include_dirs = [os.path.join(source_path, p) for p in include_dirs_rel] + ports.build_port(source_path, final, 'contrib.liblzma', flags=build_flags, exclude_files=exclude_files, includes=include_dirs) + + return [shared.cache.get_lib('liblzma.a', create, what='port')] + + +def clear(ports, settings, shared): + shared.cache.erase_lib('liblzma.a') + + +def process_args(ports): + return [] + + +config_h = ''' +#define ASSUME_RAM 128 +#define ENABLE_NLS 1 +#define HAVE_CHECK_CRC32 1 +#define HAVE_CHECK_CRC64 1 +#define HAVE_CHECK_SHA256 1 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_DCGETTEXT 1 +#define HAVE_DECL_CLOCK_MONOTONIC 1 +#define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 +#define HAVE_DECODERS 1 +#define HAVE_DECODER_ARM 1 +#define HAVE_DECODER_ARMTHUMB 1 +#define HAVE_DECODER_DELTA 1 +#define HAVE_DECODER_IA64 1 +#define HAVE_DECODER_LZMA1 1 +#define HAVE_DECODER_LZMA2 1 +#define HAVE_DECODER_POWERPC 1 +#define HAVE_DECODER_SPARC 1 +#define HAVE_DECODER_X86 1 +#define HAVE_DLFCN_H 1 +#define HAVE_ENCODERS 1 +#define HAVE_ENCODER_ARM 1 +#define HAVE_ENCODER_ARMTHUMB 1 +#define HAVE_ENCODER_DELTA 1 +#define HAVE_ENCODER_IA64 1 +#define HAVE_ENCODER_LZMA1 1 +#define HAVE_ENCODER_LZMA2 1 +#define HAVE_ENCODER_POWERPC 1 +#define HAVE_ENCODER_SPARC 1 +#define HAVE_ENCODER_X86 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FUTIMENS 1 +#define HAVE_GETOPT_H 1 +#define HAVE_GETOPT_LONG 1 +#define HAVE_GETTEXT 1 +#define HAVE_IMMINTRIN_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_MBRTOWC 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MF_BT2 1 +#define HAVE_MF_BT3 1 +#define HAVE_MF_BT4 1 +#define HAVE_MF_HC3 1 +#define HAVE_MF_HC4 1 +#define HAVE_OPTRESET 1 +#define HAVE_POSIX_FADVISE 1 +#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1 +#define HAVE_PTHREAD_PRIO_INHERIT 1 +#define HAVE_STDBOOL_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UINTPTR_T 1 +#define HAVE_UNISTD_H 1 +#define HAVE_VISIBILITY 1 +#define HAVE_WCWIDTH 1 +#define HAVE__BOOL 1 +#define HAVE___BUILTIN_ASSUME_ALIGNED 1 +#define HAVE___BUILTIN_BSWAPXX 1 +#define MYTHREAD_POSIX 1 +#define NDEBUG 1 +#define PACKAGE "xz" +#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org" +#define PACKAGE_NAME "XZ Utils" +#define PACKAGE_STRING "XZ Utils 5.4.0" +#define PACKAGE_TARNAME "xz" +#define PACKAGE_VERSION "5.4.0" +#define SIZEOF_SIZE_T 4 +#define STDC_HEADERS 1 +#define TUKLIB_CPUCORES_SYSCONF 1 +#define TUKLIB_FAST_UNALIGNED_ACCESS 1 +#define TUKLIB_PHYSMEM_SYSCONF 1 +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +#define VERSION "5.4.0" +''' From 45886e50b21fd1dee461e910267781e264574790 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 Apr 2024 18:54:10 +0100 Subject: [PATCH 026/107] Codechange: Unify where rail station tile flags are set. (#12531) This avoids repeating the logic in three places. --- src/saveload/afterload.cpp | 14 +------------- src/station_cmd.cpp | 31 ++++++++++++++++++++----------- src/station_func.h | 1 + src/waypoint_cmd.cpp | 11 +---------- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 75f062fc4b..88dee51b9c 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2878,19 +2878,7 @@ bool AfterLoadGame() /* Station blocked, wires and pylon flags need to be stored in the map. This is effectively cached data, so no * version check is necessary. This is done here as the SLV_182 check below needs the blocked status. */ for (auto t : Map::Iterate()) { - if (HasStationTileRail(t)) { - StationGfx gfx = GetStationGfx(t); - const StationSpec *statspec = GetStationSpec(t); - - bool blocked = statspec != nullptr && HasBit(statspec->blocked, gfx); - /* Default stations do not draw pylons under roofs (gfx >= 4) */ - bool pylons = statspec != nullptr ? HasBit(statspec->pylons, gfx) : gfx < 4; - bool wires = statspec == nullptr || !HasBit(statspec->wires, gfx); - - SetStationTileBlocked(t, blocked); - SetStationTileHavePylons(t, pylons); - SetStationTileHaveWires(t, wires); - } + if (HasStationTileRail(t)) SetRailStationTileFlags(t, GetStationSpec(t)); } } diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 62ef3128b3..aece206dfc 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1294,6 +1294,24 @@ static CommandCost CalculateRailStationCost(TileArea tile_area, DoCommandFlag fl return cost; } +/** + * Set rail station tile flags for the given tile. + * @param tile Tile to set flags on. + * @param statspec Statspec of the tile. + */ +void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec) +{ + const StationGfx gfx = GetStationGfx(tile); + bool blocked = statspec != nullptr && HasBit(statspec->blocked, gfx); + /* Default stations do not draw pylons under roofs (gfx >= 4) */ + bool pylons = statspec != nullptr ? HasBit(statspec->pylons, gfx) : gfx < 4; + bool wires = statspec == nullptr || !HasBit(statspec->wires, gfx); + + SetStationTileBlocked(tile, blocked); + SetStationTileHavePylons(tile, pylons); + SetStationTileHaveWires(tile, wires); +} + /** * Build rail station * @param flags operation to perform @@ -1456,18 +1474,9 @@ CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailTyp TriggerStationAnimation(st, tile, SAT_BUILT); } - /* Should be the same as layout but axis component could be wrong... */ - StationGfx gfx = GetStationGfx(tile); - bool blocked = statspec != nullptr && HasBit(statspec->blocked, gfx); - /* Default stations do not draw pylons under roofs (gfx >= 4) */ - bool pylons = statspec != nullptr ? HasBit(statspec->pylons, gfx) : gfx < 4; - bool wires = statspec == nullptr || !HasBit(statspec->wires, gfx); + SetRailStationTileFlags(tile, statspec); - SetStationTileBlocked(tile, blocked); - SetStationTileHavePylons(tile, pylons); - SetStationTileHaveWires(tile, wires); - - if (!blocked) c->infrastructure.rail[rt]++; + if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++; c->infrastructure.station++; tile += tile_delta; diff --git a/src/station_func.h b/src/station_func.h index b71130f5d8..ab24b6cc9f 100644 --- a/src/station_func.h +++ b/src/station_func.h @@ -33,6 +33,7 @@ void UpdateStationAcceptance(Station *st, bool show_msg); CargoTypes GetAcceptanceMask(const Station *st); CargoTypes GetEmptyMask(const Station *st); +void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec); const DrawTileSprites *GetStationTileLayout(StationType st, uint8_t gfx); void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image); diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index 2bf7ce5e52..0ffffcfc09 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -276,16 +276,7 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlag flags, TileIndex start_tile, Axis MakeRailWaypoint(tile, wp->owner, wp->index, axis, layout[i], GetRailType(tile)); SetCustomStationSpecIndex(tile, map_spec_index); - /* Should be the same as layout but axis component could be wrong... */ - StationGfx gfx = GetStationGfx(tile); - bool blocked = spec != nullptr && HasBit(spec->blocked, gfx); - /* Default stations do not draw pylons under roofs (gfx >= 4) */ - bool pylons = spec != nullptr ? HasBit(spec->pylons, gfx) : gfx < 4; - bool wires = spec == nullptr || !HasBit(spec->wires, gfx); - - SetStationTileBlocked(tile, blocked); - SetStationTileHavePylons(tile, pylons); - SetStationTileHaveWires(tile, wires); + SetRailStationTileFlags(tile, spec); SetRailStationReservation(tile, reserved); MarkTileDirtyByTile(tile); From 14e04685045123a81a5dc65761614a481a15b043 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 28 Jun 2024 21:41:07 +0100 Subject: [PATCH 027/107] Fix duplicate order duplicating dispatch schedule assignment --- src/order_cmd.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 4593ecf969..199104dc8d 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1065,6 +1065,7 @@ CommandCost CmdDuplicateOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, new_order.SetTravelTimetabled(false); new_order.SetTravelTime(0); new_order.SetTravelFixed(false); + new_order.SetDispatchScheduleIndex(-1); CommandCost cost = CmdInsertOrderIntl(flags, v, sel_ord + 1, new_order, true); if (cost.Failed()) return cost; if (flags & DC_EXEC) { From 72bd8966251bdbd50152e8978f536cce732f12fe Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 28 Jun 2024 22:45:52 +0100 Subject: [PATCH 028/107] Fix moving unbunch orders to another depot --- src/order_cmd.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 199104dc8d..63a74b7f9c 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -61,7 +61,14 @@ INSTANTIATE_POOL_METHODS(OrderList) btree::btree_map _order_destination_refcount_map; bool _order_destination_refcount_map_valid = false; -CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, bool allow_load_by_cargo_type); +enum CmdInsertOrderIntlFlags : uint8_t { + CIOIF_NONE = 0, ///< No flags + CIOIF_ALLOW_LOAD_BY_CARGO_TYPE = 1 << 0, ///< Allow load by cargo type + CIOIF_ALLOW_DUPLICATE_UNBUNCH = 1 << 1, ///< Allow duplicate unbunch orders +}; +DECLARE_ENUM_AS_BIT_SET(CmdInsertOrderIntlFlags) + +static CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, CmdInsertOrderIntlFlags insert_flags); void IntialiseOrderDestinationRefcountMap() { @@ -1026,7 +1033,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin VehicleOrderID sel_ord = GB(p2, 0, 16); Order new_order(p3); - return CmdInsertOrderIntl(flags, Vehicle::GetIfValid(veh), sel_ord, new_order, false); + return CmdInsertOrderIntl(flags, Vehicle::GetIfValid(veh), sel_ord, new_order, CIOIF_NONE); } /** @@ -1066,7 +1073,7 @@ CommandCost CmdDuplicateOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, new_order.SetTravelTime(0); new_order.SetTravelFixed(false); new_order.SetDispatchScheduleIndex(-1); - CommandCost cost = CmdInsertOrderIntl(flags, v, sel_ord + 1, new_order, true); + CommandCost cost = CmdInsertOrderIntl(flags, v, sel_ord + 1, new_order, CIOIF_ALLOW_LOAD_BY_CARGO_TYPE); if (cost.Failed()) return cost; if (flags & DC_EXEC) { Order *order = v->orders->GetOrderAt(sel_ord + 1); @@ -1081,7 +1088,7 @@ CommandCost CmdDuplicateOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, return CommandCost(); } -CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, bool allow_load_by_cargo_type) { +static CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, CmdInsertOrderIntlFlags insert_flags) { if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); @@ -1111,7 +1118,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s /* Filter invalid load/unload types. */ switch (new_order.GetLoadType()) { case OLFB_CARGO_TYPE_LOAD: - if (allow_load_by_cargo_type) break; + if ((insert_flags & CIOIF_ALLOW_LOAD_BY_CARGO_TYPE) != 0) break; return CMD_ERROR; case OLF_LOAD_IF_POSSIBLE: @@ -1129,7 +1136,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s switch (new_order.GetUnloadType()) { case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break; case OUFB_CARGO_TYPE_UNLOAD: - if (allow_load_by_cargo_type) break; + if ((insert_flags & CIOIF_ALLOW_LOAD_BY_CARGO_TYPE) != 0) break; return CMD_ERROR; default: return CMD_ERROR; } @@ -1203,7 +1210,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s /* Check if we're allowed to have a new unbunching order. */ if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) { if (v->HasFullLoadOrder()) return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD); - if (v->HasUnbunchingOrder()) return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED); + if ((insert_flags & CIOIF_ALLOW_DUPLICATE_UNBUNCH) == 0 && v->HasUnbunchingOrder()) return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED); if (v->HasConditionalOrder()) return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL); } break; @@ -1835,7 +1842,7 @@ CommandCost CmdReverseOrderList(TileIndex tile, DoCommandFlag flags, uint32_t p1 new_order.SetTravelTimetabled(false); new_order.SetTravelTime(0); new_order.SetTravelFixed(false); - CommandCost cost = CmdInsertOrderIntl(flags, v, order_count, new_order, true); + CommandCost cost = CmdInsertOrderIntl(flags, v, order_count, new_order, CIOIF_ALLOW_LOAD_BY_CARGO_TYPE); if (cost.Failed()) return cost; if (flags & DC_EXEC) { Order *order = v->orders->GetOrderAt(order_count); @@ -3888,7 +3895,7 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, const bool wait_timetabled = wait_fixed && new_order.IsWaitTimetabled(); new_order.SetWaitTimetabled(false); new_order.SetTravelTimetabled(false); - if (CmdInsertOrderIntl(flags, v, index + 1, new_order, true).Succeeded()) { + if (CmdInsertOrderIntl(flags, v, index + 1, new_order, CIOIF_ALLOW_LOAD_BY_CARGO_TYPE | CIOIF_ALLOW_DUPLICATE_UNBUNCH).Succeeded()) { DoCommand(0, v->index, index, flags, CMD_DELETE_ORDER); order = v->orders->GetOrderAt(index); From f21618a987720e53a978dabfb109a9558c6a3678 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 28 Jun 2024 22:25:29 +0100 Subject: [PATCH 029/107] Preserve wait time/timetabled state when duplicating or mass changing order --- src/order_cmd.cpp | 25 +++++++++---------------- src/timetable_cmd.cpp | 4 ++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 63a74b7f9c..98d931e153 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -70,6 +70,8 @@ DECLARE_ENUM_AS_BIT_SET(CmdInsertOrderIntlFlags) static CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, CmdInsertOrderIntlFlags insert_flags); +extern void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled, bool wait_fixed); + void IntialiseOrderDestinationRefcountMap() { ClearOrderDestinationRefcountMap(); @@ -1067,7 +1069,7 @@ CommandCost CmdDuplicateOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, Order new_order; new_order.AssignOrder(*src_order); const bool wait_fixed = new_order.IsWaitFixed(); - const bool wait_timetabled = wait_fixed && new_order.IsWaitTimetabled(); + const bool wait_timetabled = new_order.IsWaitTimetabled(); new_order.SetWaitTimetabled(false); new_order.SetTravelTimetabled(false); new_order.SetTravelTime(0); @@ -1079,10 +1081,7 @@ CommandCost CmdDuplicateOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, Order *order = v->orders->GetOrderAt(sel_ord + 1); order->SetRefit(new_order.GetRefitCargo()); order->SetMaxSpeed(new_order.GetMaxSpeed()); - if (wait_fixed) { - extern void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled); - SetOrderFixedWaitTime(v, sel_ord + 1, new_order.GetWaitTime(), wait_timetabled); - } + SetOrderFixedWaitTime(v, sel_ord + 1, new_order.GetWaitTime(), wait_timetabled, wait_fixed); } new_order.Free(); return CommandCost(); @@ -1837,7 +1836,7 @@ CommandCost CmdReverseOrderList(TileIndex tile, DoCommandFlag flags, uint32_t p1 Order new_order; new_order.AssignOrder(*v->GetOrder(i)); const bool wait_fixed = new_order.IsWaitFixed(); - const bool wait_timetabled = wait_fixed && new_order.IsWaitTimetabled(); + const bool wait_timetabled = new_order.IsWaitTimetabled(); new_order.SetWaitTimetabled(false); new_order.SetTravelTimetabled(false); new_order.SetTravelTime(0); @@ -1848,10 +1847,7 @@ CommandCost CmdReverseOrderList(TileIndex tile, DoCommandFlag flags, uint32_t p1 Order *order = v->orders->GetOrderAt(order_count); order->SetRefit(new_order.GetRefitCargo()); order->SetMaxSpeed(new_order.GetMaxSpeed()); - if (wait_fixed) { - extern void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled); - SetOrderFixedWaitTime(v, order_count, new_order.GetWaitTime(), wait_timetabled); - } + SetOrderFixedWaitTime(v, order_count, new_order.GetWaitTime(), wait_timetabled, wait_fixed); } new_order.Free(); } @@ -3892,19 +3888,16 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, new_order.AssignOrder(*order); new_order.SetDestination(to_dest); const bool wait_fixed = new_order.IsWaitFixed(); - const bool wait_timetabled = wait_fixed && new_order.IsWaitTimetabled(); + const bool wait_timetabled = new_order.IsWaitTimetabled(); new_order.SetWaitTimetabled(false); - new_order.SetTravelTimetabled(false); + if (!new_order.IsTravelFixed()) new_order.SetTravelTimetabled(false); if (CmdInsertOrderIntl(flags, v, index + 1, new_order, CIOIF_ALLOW_LOAD_BY_CARGO_TYPE | CIOIF_ALLOW_DUPLICATE_UNBUNCH).Succeeded()) { DoCommand(0, v->index, index, flags, CMD_DELETE_ORDER); order = v->orders->GetOrderAt(index); order->SetRefit(new_order.GetRefitCargo()); order->SetMaxSpeed(new_order.GetMaxSpeed()); - if (wait_fixed) { - extern void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled); - SetOrderFixedWaitTime(v, index, new_order.GetWaitTime(), wait_timetabled); - } + SetOrderFixedWaitTime(v, index, new_order.GetWaitTime(), wait_timetabled, wait_fixed); changed = true; } diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 1418da4bf3..004b068ab9 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -1094,7 +1094,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) SetTimetableWindowsDirty(v); } -void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled) { +void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32_t wait_time, bool wait_timetabled, bool wait_fixed) { ChangeTimetable(v, order_number, wait_time, MTF_WAIT_TIME, wait_timetabled, true); - ChangeTimetable(v, order_number, 1, MTF_SET_WAIT_FIXED, false, true); + ChangeTimetable(v, order_number, wait_fixed ? 1 : 0, MTF_SET_WAIT_FIXED, false, true); } From 41dbd2ade2cd029371618fb64c69ae26dce3370d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 28 Jun 2024 23:24:22 +0100 Subject: [PATCH 030/107] Fix struct/class mismatch for BitmapTileArea --- src/bitmap_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmap_type.h b/src/bitmap_type.h index bd722f346e..132d56d920 100644 --- a/src/bitmap_type.h +++ b/src/bitmap_type.h @@ -22,7 +22,7 @@ * A std::vector is used to mark which tiles are contained. */ class BitmapTileArea : public TileArea { - friend struct BitmapTileIterator; + friend class BitmapTileIterator; protected: using BlockT = uint32_t; From 9a342e489dae8111ec929e489a07b11766e3af53 Mon Sep 17 00:00:00 2001 From: Fedello <31769405+pvillaverde@users.noreply.github.com> Date: Sat, 29 Jun 2024 00:25:03 +0200 Subject: [PATCH 031/107] =?UTF-8?q?=F0=9F=8C=90=20Update=20galician=20Tran?= =?UTF-8?q?slations=202024-06-28=20(#708)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lang/extra/galician.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/lang/extra/galician.txt b/src/lang/extra/galician.txt index 9dd92e842c..1036714834 100644 --- a/src/lang/extra/galician.txt +++ b/src/lang/extra/galician.txt @@ -155,6 +155,13 @@ STR_CONFIG_SETTING_REALISTIC_BRAKING_ASPECT_LIMITED_HELPTEXT :No modelo de fr STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION :Limitar a aceleración dos trens: {STRING} STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION_HELPTEXT :Ao usar o modelo realista de frenado de trens, tamén limitar a aceleración máxima dos trens. Isto é para evitar que os pasaxeiros derramen as súas bebidas debido a que algúns tipos de trens aceleran excesivamente rápido.. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT :Factor da escala de aceleración/freado do tren: {STRING} +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_HELPTEXT :A porcentaxe pola que se axusta a aceleración e o frenado do tren.{}{}Esta configuración pode usarse para alterar a aceleración e o frenado dos trens, sen cambiar a velocidade máxima dos trens. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_VALUE :{COMMA}% + +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING :A edición de vías ignora o frenado realista: {STRING} +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING_HELPTEXT :Permitir que a edición de vías ignore o modelo de frenado realista dos trens. Cando está habilitado, non se aplican restricións á edición/eliminación da reserva dos trens en movemento. Isto pode resultar nun comportamento de frenado do tren non realista. + STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT :Velocidade máxima de carga en movemento do tren: {STRING} STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT_HELPTEXT :A velocidade máxima permitida os trens cando están cargando en movemento @@ -1517,6 +1524,7 @@ STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON :{BLACK}Renomear STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON :{BLACK}Renomear vagón STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP :{BLACK}Renomear locomotora ou coche motriz STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP :{BLACK}Renomear vagón +STR_BUY_VEHICLE_TRAIN_TOGGLE_DUAL_PANE_TOOLTIP :{BLACK}Alternar entre locomotoras e vagóns separados STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION :{WHITE}Renomear tipo de locomotora STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION :{WHITE}Renomear tipo de vagón @@ -1665,8 +1673,12 @@ STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST :é o primeiro s STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST :non é o primeiro slot STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST :é o último slot STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST :non é o último slot + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :ten a etiqueta {NUM} +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG_NAMED :ten a etiqueta {NUM} ({STRING}) + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :non ten a etiqueta {NUM} +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG_NAMED :non ten a etiqueta {NUM} ({STRING}) STR_ORDERS_MANAGE_LIST :{BLACK}Xestionar lista STR_ORDERS_MANAGE_LIST_TOOLTIP :{BLACK}Xestiona esta lista de ordes @@ -2133,10 +2145,16 @@ STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}Engadir STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP :{BLACK}Engadir as programacións dende outro vehículo. STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS :Reutilizar franxas de saída STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}Establecer se as franxas de saída poden ser usadas máis dunha vez. +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG :Renomear etiqueta {NUM} +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_NAMED :Renomear etiqueta {NUM}: {STRING} +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP :{BLACK}Renomear etiquetas de slot de saída (para usar con ordes condicionais) +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_CAPTION :{BLACK}Nomear a etiqueta do slot de saída +STR_ERROR_CAN_T_RENAME_DEPARTURE_TAG :{WHITE}Non se pode nomear a etiqueta de saída... STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}Xestionar Slot STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT :Reutilizar este slot de saída STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP :{BLACK}Establecer se a franxa de saída seleccionada pode ser utilizada máis dunha vez. STR_SCHDISPATCH_TAG_DEPARTURE :Etiqueta {NUM} +STR_SCHDISPATCH_TAG_DEPARTURE_NAMED :Etiqueta {NUM}: {STRING} STR_SCHDISPATCH_TAG_DEPARTURE_TOOLTIP :{BLACK}Etiquetar a franxa de saída seleccionada (para usar con ordes condicionais). STR_SCHDISPATCH_NO_SCHEDULES :{BLACK}Sen programas STR_SCHDISPATCH_SCHEDULE_ID :{BLACK}Programa {NUM} de {NUM} @@ -2153,6 +2171,7 @@ STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}Seguinte slot STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE :{}O slot de saída pódese usar máis dunha vez STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({TT_TIME}) STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}Etiqueta {NUM} +STR_SCHDISPATCH_SLOT_TOOLTIP_TAG_NAMED :{}Etiqueta {NUM}: {STRING} STR_SCHDISPATCH_SUMMARY_NO_LAST_DEPARTURE :{BLACK}Sen saídas previas. STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Última saída ás {TT_TIME}. From f1504dcc345eb484ecef03a4cd03017d1245b6fb Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 30 Jun 2024 13:05:24 +0100 Subject: [PATCH 032/107] Improve link graph refresher when using autorefit with cargo-type load orders --- src/linkgraph/refresh.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linkgraph/refresh.cpp b/src/linkgraph/refresh.cpp index 08808cc6f2..bd49343b1a 100644 --- a/src/linkgraph/refresh.cpp +++ b/src/linkgraph/refresh.cpp @@ -387,7 +387,9 @@ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, TimetableT SetBit(flags, IN_AUTOREFIT); LinkRefresher backup(*this); for (CargoID c = 0; c != NUM_CARGO; ++c) { - if (CargoSpec::Get(c)->IsValid() && this->HandleRefit(c)) { + if (!CargoSpec::Get(c)->IsValid()) continue; + if (next->GetCargoLoadType(c) == OLFB_NO_LOAD) continue; + if (this->HandleRefit(c)) { this->RefreshLinks(cur, next, travel, flags, num_hops); *this = backup; } From f8b008cd283fff90dcde4c8749c04afebea62e79 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 30 Jun 2024 13:12:53 +0100 Subject: [PATCH 033/107] Avoid unnecessary GoodsEntryData creation --- src/cargopacket.cpp | 2 +- src/linkgraph/linkgraphjob.cpp | 1 + src/station_base.h | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index aafd23eb9a..19cc32ea33 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -636,7 +636,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID CargoPacketList transfer_deliver; std::vector keep; - const FlowStatMap &flows = ge->CreateData().flows; + const FlowStatMap &flows = ge->ConstFlows(); bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0; bool force_unload = (order_flags & OUFB_UNLOAD) != 0; diff --git a/src/linkgraph/linkgraphjob.cpp b/src/linkgraph/linkgraphjob.cpp index 126187fb37..d486aa2c00 100644 --- a/src/linkgraph/linkgraphjob.cpp +++ b/src/linkgraph/linkgraphjob.cpp @@ -182,6 +182,7 @@ void LinkGraphJob::FinaliseJob() geflows.insert(std::move(*it)); } geflows.SortStorage(); + ge.RemoveDataIfUnused(); InvalidateWindowData(WC_STATION_VIEW, st->index, this->Cargo()); } } diff --git a/src/station_base.h b/src/station_base.h index 9e8f47642f..360c742370 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -715,6 +715,11 @@ struct GoodsEntry { { return this->data != nullptr ? this->data->flows : _empty_flows; } + + void RemoveDataIfUnused() + { + if (this->data != nullptr && this->data->MayBeRemoved()) this->data.reset(); + } }; /** All airport-related information. Only valid if tile != INVALID_TILE. */ From bea66c4bebd6bb34fa587d5ebfe6788953bd79da Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 30 Jun 2024 19:12:08 +0100 Subject: [PATCH 034/107] Fix minor code style issue --- src/pathfinder/yapf/yapf_costrail.hpp | 6 +++--- src/pbs.cpp | 6 +++--- src/signal.cpp | 4 ++-- src/train_cmd.cpp | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index f8a9f0fd97..d9ed73c2d5 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -300,7 +300,7 @@ private: if (GetSignalType(tile, TrackdirToTrack(trackdir)) == SIGTYPE_PBS && !HasSignalOnTrackdir(tile, trackdir)) { flags_to_check |= TRPAUF_REVERSE; } - if (prog && prog->actions_used_flags & flags_to_check) { + if (prog != nullptr && prog->actions_used_flags & flags_to_check) { prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out); if (out.flags & TRPRF_RESERVE_THROUGH && is_res_through != nullptr) { *is_res_through = true; @@ -326,7 +326,7 @@ private: { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); TraceRestrictProgramActionsUsedFlags flags_to_check = TRPAUF_PF; - if (prog && prog->actions_used_flags & flags_to_check) { + if (prog != nullptr && prog->actions_used_flags & flags_to_check) { prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out); if (out.flags & TRPRF_DENY) { n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; @@ -428,7 +428,7 @@ public: if (IsNoEntrySignal(sig_type)) { if (ShouldCheckTraceRestrict(n, tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & TRPAUF_PF) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_PF) { TraceRestrictProgramResult out; prog->Execute(Yapf().GetVehicle(), TraceRestrictProgramInput(tile, trackdir, &TraceRestrictPreviousSignalCallback, &n), out); if (out.flags & TRPRF_DENY) { diff --git a/src/pbs.cpp b/src/pbs.cpp index 5608c059fc..80d0fdc44d 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -366,7 +366,7 @@ static uint16_t ApplyTunnelBridgeLookaheadSignalSpeedRestriction(TileIndex tile, trackdir = GetTunnelBridgeExitTrackdir(tile); } const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & TRPAUF_SPEED_RESTRICTION) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_SPEED_RESTRICTION) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(tile, trackdir, nullptr, nullptr); prog->Execute(v, input, out); @@ -650,7 +650,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra uint16_t speed_restriction = lookahead->speed_restriction; if (v != nullptr) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & au_flags) { + if (prog != nullptr && prog->actions_used_flags & au_flags) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(tile, trackdir, nullptr, nullptr); prog->Execute(v, input, out); @@ -1507,7 +1507,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo if (GetSignalAlwaysReserveThrough(ft.m_new_tile, TrackdirToTrack(td))) return false; if (IsRestrictedSignal(ft.m_new_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(ft.m_new_tile, TrackdirToTrack(td)); - if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH) { TraceRestrictProgramResult out; prog->Execute(v, TraceRestrictProgramInput(ft.m_new_tile, td, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr), out); if (out.flags & TRPRF_RESERVE_THROUGH) { diff --git a/src/signal.cpp b/src/signal.cpp index 8d117489f2..4a70410028 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -1576,7 +1576,7 @@ void DetermineCombineNormalShuntModeWithLookahead(Train *v, TileIndex tile, Trac if (IsRestrictedSignal(tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & TRPAUF_CMB_SIGNAL_MODE_CTRL) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_CMB_SIGNAL_MODE_CTRL) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(tile, trackdir, [](const Train *v, const void *, TraceRestrictPBSEntrySignalAuxField mode) { if (mode == TRPESAF_RES_END_TILE) { @@ -1973,7 +1973,7 @@ void UpdateSignalReserveThroughBit(TileIndex tile, Track track, bool update_sign } else { if (IsRestrictedSignal(tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, track); - if (prog && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH_ALWAYS) reserve_through = true; + if (prog != nullptr && prog->actions_used_flags & TRPAUF_RESERVE_THROUGH_ALWAYS) reserve_through = true; } } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index d6f01a8f09..af16cc7e8e 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4258,7 +4258,7 @@ static bool HasLongReservePbsSignalOnTrackdir(Train* v, TileIndex tile, Trackdir if (IsNoEntrySignal(tile, TrackdirToTrack(trackdir))) return false; if (IsRestrictedSignal(tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & TRPAUF_LONG_RESERVE) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_LONG_RESERVE) { TraceRestrictProgramResult out; if (default_value) out.flags |= TRPRF_LONG_RESERVE; TraceRestrictProgramInput input(tile, trackdir, &VehiclePosTraceRestrictPreviousSignalCallback, nullptr); @@ -4441,7 +4441,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir)) && !IsNoEntrySignal(tile, track)) { if (IsRestrictedSignal(tile) && v->force_proceed != TFP_SIGNAL) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, track); - if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_TRAIN_NOT_STUCK)) { + if (prog != nullptr && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE | TRPAUF_TRAIN_NOT_STUCK)) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(tile, TrackEnterdirToTrackdir(track, enterdir), nullptr, nullptr); input.permitted_slot_operations = TRPISP_ACQUIRE; @@ -5326,7 +5326,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile) auto try_exit_reservation = [&]() -> bool { if (IsTunnelBridgeRestrictedSignal(tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(tile, TrackdirToTrack(td)); - if (prog && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE)) { + if (prog != nullptr && prog->actions_used_flags & (TRPAUF_WAIT_AT_PBS | TRPAUF_SLOT_ACQUIRE)) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(tile, td, nullptr, nullptr); input.permitted_slot_operations = TRPISP_ACQUIRE; @@ -5932,7 +5932,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (IsTunnelBridgeRestrictedSignal(old_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track); - if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); input.permitted_slot_operations = TRPISP_RELEASE_BACK; @@ -6173,7 +6173,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (HasSignalOnTrack(gp.old_tile, track)) { if (IsRestrictedSignal(gp.old_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); - if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr); input.permitted_slot_operations = TRPISP_RELEASE_BACK; @@ -6191,7 +6191,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) { if (IsTunnelBridgeRestrictedSignal(gp.old_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); - if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { + if (prog != nullptr && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr); input.permitted_slot_operations = TRPISP_RELEASE_BACK; From 78fdb09e2b3cf54e972a6e0262c3edaeb4625c8d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 30 Jun 2024 19:33:47 +0100 Subject: [PATCH 035/107] Add setting for auto-fill drag signal removal to stop at restricted signal Default on --- src/lang/extra/english.txt | 4 +++ src/rail_cmd.cpp | 39 ++++++++++++++++++----------- src/rail_gui.cpp | 1 + src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings/gui_settings.ini | 8 ++++++ 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 9899cb5b35..cab5541111 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -816,6 +816,9 @@ STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_ANYWHERE :Anywhere STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS :When auto-fill dragging, continue past stations/waypoints: {STRING2} STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS_HELPTEXT :Select the behaviour of signal placement when Ctrl+dragging signals. If disabled, signal placement stops when reaching a station/waypoint tile. If enabled, signal placement continues on the far side of rail stations/waypoints +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL :When removing signals using auto-fill drag, stop at restricted signals: {STRING2} +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL_HELPTEXT :Select the behaviour of signal placement when removing signal using Ctrl+dragging. If enabled, removal of signals stops when reaching a signal with an attached routing restriction program + STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED :{WHITE}Can't change setting... STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED_NEWGRF :{WHITE}...setting is observed by a NewGRF @@ -1959,6 +1962,7 @@ STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}Can't bu STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}Can't remove road waypoint here... STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST :{WHITE}Must remove road waypoint first STR_ERROR_UNSUITABLE_SIGNAL_TYPE :{WHITE}... unsuitable signal type +STR_ERROR_RESTRICTED_SIGNAL :{WHITE}... signal has attached routing restriction program STR_ERROR_SIGNAL_CHANGES :{WHITE}Number of programmable pre-signal evaluations exceeded limit STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION :{WHITE}Bridge is too low for station diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index be75995918..dc277f2515 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1473,17 +1473,18 @@ static void ReReserveTrainPath(Train *v) * @param tile tile where to build the signals * @param flags operation to perform * @param p1 various bitstuffed elements - * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum) - * - p1 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal or (for bit 7) toggle variant (CTRL-toggle) - * - p1 = (bit 4) - 0 = signals, 1 = semaphores - * - p1 = (bit 5-7) - type of the signal, for valid values see enum SignalType in rail_map.h - * - p1 = (bit 8) - convert the present signal type and variant - * - p1 = (bit 9-10)- cycle through which signal sets? - * - p1 = (bit 15-16)-cycle the signal direction this many times - * - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type - * - p1 = (bit 18) - permit creation of/conversion to bidirectionally signalled bridges/tunnels - * - p1 = (bit 19-22)-signal style - * - p1 = (bit 23-27)-signal spacing + * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum) + * - p1 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal or (for bit 7) toggle variant (CTRL-toggle) + * - p1 = (bit 4) - 0 = signals, 1 = semaphores + * - p1 = (bit 5-7) - type of the signal, for valid values see enum SignalType in rail_map.h + * - p1 = (bit 8) - convert the present signal type and variant + * - p1 = (bit 9-10) - cycle through which signal sets? + * - p1 = (bit 15-16) - cycle the signal direction this many times + * - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type + * - p1 = (bit 18) - permit creation of/conversion to bidirectionally signalled bridges/tunnels + * - p1 = (bit 19-22) - signal style + * - p1 = (bit 23-27) - signal spacing + * - p1 = (bit 28) - disallow removing restricted signals * @param p2 used for CmdBuildManySignals() to copy direction of first signal * @param text unused * @return the cost of this operation or an error @@ -1983,6 +1984,7 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal * - p2 = (bit 24-31) - user defined signals_density * @param p3 various bitstuffed elements * - p3 = (bit 0) - 1 = skip over rail stations/waypoints, 0 = stop at rail stations/waypoints + * - p3 = (bit 1) - 1 = stop at restricted signals on remove, 0 = allow removing restricted signals * @param text unused * @return the cost of this operation or an error */ @@ -2000,6 +2002,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin uint8_t signal_density = GB(p2, 24, 8); uint8_t signal_style = GB(p2, 11, 4); bool allow_station = HasBit(p3, 0); + bool no_remove_restricted_signal = HasBit(p3, 1); if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR; TileIndex end_tile = p1; @@ -2088,6 +2091,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin SB(param1, 19, 4, signal_style); if (!remove && signal_ctr == 0) SetBit(param1, 17); if (!remove) SB(param1, 23, 5, Clamp(GB(p2, 24, 8), 1, 16)); + if (remove && no_remove_restricted_signal) SetBit(param1, 28); /* Pick the correct orientation for the track direction */ signals = 0; @@ -2107,6 +2111,9 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin last_suitable_ctr = signal_ctr; last_suitable_tile = tile; last_suitable_trackdir = trackdir; + } else if (ret.GetErrorMessage() == STR_ERROR_RESTRICTED_SIGNAL) { + last_error = ret; + break; } else if (!test_only && last_suitable_tile != INVALID_TILE && ret.GetErrorMessage() != STR_ERROR_CANNOT_MODIFY_TRACK_TRAIN_APPROACHING) { /* If a signal can't be placed, place it at the last possible position. */ SB(param1, 0, 3, TrackdirToTrack(last_suitable_trackdir)); @@ -2183,6 +2190,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uin * - p2 = (bit 24-31) - user defined signals_density * @param p3 various bitstuffed elements * - p3 = (bit 0) - 1 = skip over rail stations/waypoints, 0 = stop at rail stations/waypoints + * - p3 = (bit 1) - 1 = stop at restricted signals on remove, 0 = allow removing restricted signals * @param text unused * @return the cost of this operation or an error * @see CmdSignalTrackHelper @@ -2196,10 +2204,9 @@ CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32_t p1 * Remove signals * @param tile coordinates where signal is being deleted from * @param flags operation to perform - * @param p1 various bitstuffed elements, only track information is used + * @param p1 various bitstuffed elements, only relevant bits shown, see CmdBuildSingleSignal for full list * - (bit 0- 2) - track-orientation, valid values: 0-5 (Track enum) - * - (bit 3) - override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) - * - (bit 4) - 0 = signals, 1 = semaphores + * - (bit 28) - disallow removing restricted signals * @param p2 unused * @param text unused * @return the cost of this operation or an error @@ -2207,6 +2214,7 @@ CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32_t p1 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, const char *text) { Track track = Extract(p1); + bool no_remove_restricted = HasBit(p1, 28); Money cost = _price[PR_CLEAR_SIGNALS]; if (IsTileType(tile, MP_TUNNELBRIDGE)) { @@ -2216,6 +2224,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t } if (!IsTunnelBridgeWithSignalSimulation(tile)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); TileIndex end = GetOtherTunnelBridgeEnd(tile); + if (no_remove_restricted && (IsTunnelBridgeRestrictedSignal(tile) || IsTunnelBridgeRestrictedSignal(end))) return_cmd_error(STR_ERROR_RESTRICTED_SIGNAL); CommandCost ret = TunnelBridgeIsFree(tile, end, nullptr, TBIFM_ACROSS_ONLY); if (ret.Failed()) return ret; @@ -2227,6 +2236,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t if (!HasSignalOnTrack(tile, track)) { return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); } + if (no_remove_restricted && GetExistingTraceRestrictProgram(tile, track) != nullptr) return_cmd_error(STR_ERROR_RESTRICTED_SIGNAL); } /* Only water can remove signals from anyone */ @@ -2326,6 +2336,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t * - p2 = (bit 24-31) - user defined signals_density * @param p3 various bitstuffed elements * - p3 = (bit 0) - 1 = skip over rail stations/waypoints, 0 = stop at rail stations/waypoints + * - p3 = (bit 1) - 1 = stop at restricted signals on remove, 0 = allow removing restricted signals * @param text unused * @return the cost of this operation or an error * @see CmdSignalTrackHelper diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index e742e07b34..6995f9afee 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -496,6 +496,7 @@ static void HandleAutoSignalPlacement() SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); } SB(p3, 0, 1, _settings_client.gui.drag_signals_skip_stations); + SB(p3, 1, 1, _ctrl_pressed && _settings_client.gui.drag_signals_stop_restricted_signal); /* _settings_client.gui.drag_signals_density is given as a parameter such that each user * in a network game can specify their own signal density */ diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 957a904c0b..cbcc900d3a 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2356,6 +2356,7 @@ static SettingsContainer &GetSettingsTree() signals->Add(new SettingEntry("gui.cycle_signal_types")); signals->Add(new SettingEntry("gui.drag_signals_fixed_distance")); signals->Add(new SettingEntry("gui.drag_signals_skip_stations")); + signals->Add(new SettingEntry("gui.drag_signals_stop_restricted_signal")); signals->Add(new SettingEntry("gui.auto_remove_signals")); signals->Add(new SettingEntry("gui.show_restricted_signal_recolour")); signals->Add(new SettingEntry("gui.show_all_signal_default")); diff --git a/src/settings_type.h b/src/settings_type.h index 29ea37b86f..f43fb3da69 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -262,6 +262,7 @@ struct GUISettings : public TimeSettings { uint8_t drag_signals_density; ///< many signals density bool drag_signals_fixed_distance; ///< keep fixed distance between signals when dragging bool drag_signals_skip_stations; ///< continue past station/waypoint tiles when auto-fill dragging signals + bool drag_signals_stop_restricted_signal; ///< when removing signals using auto-fill drag, sto pwhen reaching a signal with an attached routing restriction CalTime::Year semaphore_build_before; ///< build semaphore signals automatically before this year uint8_t news_message_timeout; ///< how much longer than the news message "age" should we keep the message in the history bool show_track_reservation; ///< highlight reserved tracks. diff --git a/src/table/settings/gui_settings.ini b/src/table/settings/gui_settings.ini index 743255a60f..854a1459f8 100644 --- a/src/table/settings/gui_settings.ini +++ b/src/table/settings/gui_settings.ini @@ -1096,6 +1096,14 @@ str = STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS strhelp = STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS_HELPTEXT cat = SC_EXPERT +[SDTC_BOOL] +var = gui.drag_signals_stop_restricted_signal +flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_PATCH +def = true +str = STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL +strhelp = STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL_HELPTEXT +cat = SC_EXPERT + [SDTC_VAR] var = gui.semaphore_build_before type = SLE_INT32 From f5b0874c1cdf4d05f52a263aa081d0a8fb42ec52 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 1 Jul 2024 20:39:32 +0100 Subject: [PATCH 036/107] Do not unnecessarily update town label if local rating unchanged --- src/town.h | 2 +- src/town_cmd.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/town.h b/src/town.h index fdd563d4e6..810bc84d9d 100644 --- a/src/town.h +++ b/src/town.h @@ -168,7 +168,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { return ClampTo((this->cache.population / _settings_game.economy.town_noise_population[_settings_game.difficulty.town_council_tolerance]) + 3); } - void UpdateVirtCoord(); + void UpdateVirtCoord(bool only_if_label_changed = false); inline const char *GetCachedName() const { diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 70cd052548..3da9bdf7a7 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -532,10 +532,14 @@ static bool IsCloseToTown(TileIndex tile, uint dist) } /** Resize the sign (label) of the town after it changes population. */ -void Town::UpdateVirtCoord() +void Town::UpdateVirtCoord(bool only_if_label_changed) { if (IsHeadless()) return; + + auto label_rating = this->town_label_rating; this->UpdateLabel(); + if (only_if_label_changed && label_rating == this->town_label_rating) return; + Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); if (_viewport_sign_kdtree_valid && this->cache.sign.kdtree_valid) _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeTown(this->index)); @@ -4142,7 +4146,7 @@ static void UpdateTownRating(Town *t) t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM); } - t->UpdateVirtCoord(); + t->UpdateVirtCoord(true); SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } From a99e6b5082f36267c836ddd4b5e2f896232748bc Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 1 Jul 2024 23:40:11 +0100 Subject: [PATCH 037/107] Delay vehicle cache init to after map upgrades in load Split AfterLoadVehicles into two functions. Vehicle cache init and other functionality requiring an upgraded and valid map is now performed later in the load process. Re-order load update for SLV_139, it is no longer required to be performed before the first phase of vehicle updates --- src/elrail.cpp | 14 +++++++++---- src/elrail_func.h | 1 + src/order_base.h | 2 +- src/saveload/afterload.cpp | 41 +++++++++++++++++++------------------ src/saveload/vehicle_sl.cpp | 1 - src/sl/saveload_internal.h | 3 ++- src/sl/vehicle_sl.cpp | 33 +++++++++++++++++------------ src/vehicle_base.h | 2 +- 8 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/elrail.cpp b/src/elrail.cpp index abfc0ed150..16e82ae3e0 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -703,7 +703,11 @@ void DrawRailCatenary(const TileInfo *ti) void SettingsDisableElrail(int32_t new_value) { bool disable = (new_value != 0); + UpdateDisableElrailSettingState(disable, true); +} +void UpdateDisableElrailSettingState(bool disable, bool update_vehicles) +{ /* pick appropriate railtype for elrail engines depending on setting */ const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC; @@ -731,10 +735,12 @@ void SettingsDisableElrail(int32_t new_value) } /* Fix the total power and acceleration for trains */ - for (Train *t : Train::IterateFrontOnly()) { - /* power and acceleration is cached only for front engines */ - if (t->IsFrontEngine()) { - t->ConsistChanged(CCF_TRACK); + if (update_vehicles) { + 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/elrail_func.h b/src/elrail_func.h index 124dffb0b9..3f6ca0cee1 100644 --- a/src/elrail_func.h +++ b/src/elrail_func.h @@ -37,5 +37,6 @@ void DrawRailCatenaryOnTunnel(const TileInfo *ti); void DrawRailCatenaryOnBridge(const TileInfo *ti); void SettingsDisableElrail(int32_t new_value); ///< _settings_game.disable_elrail callback +void UpdateDisableElrailSettingState(bool disable, bool update_vehicles); #endif /* ELRAIL_FUNC_H */ diff --git a/src/order_base.h b/src/order_base.h index 559d78c5c9..80e44bc33e 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -890,7 +890,7 @@ static_assert(DispatchSchedule::DEPARTURE_TAG_COUNT == 1 + (DispatchSlot::SDSF_L */ struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { private: - friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain + friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< For instantiating the shared vehicle chain friend SaveLoadTable GetOrderListDescription(); ///< Saving and loading of order lists. friend upstream_sl::SaveLoadTable upstream_sl::GetOrderListDescription(); ///< Saving and loading of order lists. friend void Ptrs_ORDL(); ///< Saving and loading of order lists. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index d3e432e9d4..e849ce2693 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -985,17 +985,6 @@ bool AfterLoadGame() * filled; and that could eventually lead to desyncs. */ CargoPacket::AfterLoad(); - /* Oilrig was moved from id 15 to 9. We have to do this conversion - * here as AfterLoadVehicles can check it indirectly via the newgrf - * code. */ - if (IsSavegameVersionBefore(SLV_139)) { - for (Station *st : Station::Iterate()) { - if (st->airport.tile != INVALID_TILE && st->airport.type == 15) { - st->airport.type = AT_OILRIG; - } - } - } - if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { /* * Reject huge airports @@ -1061,8 +1050,8 @@ bool AfterLoadGame() extern void AnalyseHouseSpriteGroups(); AnalyseHouseSpriteGroups(); - /* Update all vehicles */ - AfterLoadVehicles(true); + /* Update all vehicles: Phase 1 */ + AfterLoadVehiclesPhase1(true); CargoPacket::PostVehiclesAfterLoad(); @@ -1747,11 +1736,6 @@ bool AfterLoadGame() SetSecondaryRailType(t, GetRailType(t)); } } - - for (Train *v : Train::IterateFrontOnly()) { - if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(CCF_TRACK); - } - } /* In version 16.1 of the savegame a company can decide if trains, which get @@ -1900,7 +1884,7 @@ bool AfterLoadGame() * preference of a user, let elrails enabled; it can be disabled manually */ if (IsSavegameVersionBefore(SLV_38)) _settings_game.vehicle.disable_elrails = false; /* do the same as when elrails were enabled/disabled manually just now */ - SettingsDisableElrail(_settings_game.vehicle.disable_elrails); + UpdateDisableElrailSettingState(_settings_game.vehicle.disable_elrails, false); InitializeRailGUI(); /* From version 53, the map array was changed for house tiles to allow @@ -2872,6 +2856,14 @@ bool AfterLoadGame() } } + if (IsSavegameVersionBefore(SLV_139)) { + for (Station *st : Station::Iterate()) { + if (st->airport.tile != INVALID_TILE && st->airport.type == 15) { + st->airport.type = AT_OILRIG; + } + } + } + if (IsSavegameVersionBefore(SLV_140)) { for (Station *st : Station::Iterate()) { if (st->airport.tile != INVALID_TILE) { @@ -3469,6 +3461,14 @@ bool AfterLoadGame() } } + /* Beyond this point, tile types which can be accessed by vehicles must be in a valid state. */ + + /* Update all vehicles: Phase 2 */ + AfterLoadVehiclesPhase2(true); + + /* The center of train vehicles was changed, fix up spacing. */ + if (IsSavegameVersionBefore(SLV_164)) FixupTrainLengths(); + /* In version 2.2 of the savegame, we have new airports, so status of all aircraft is reset. * This has to be called after all map array updates */ if (IsSavegameVersionBefore(SLV_2, 2)) UpdateOldAircraft(); @@ -4580,7 +4580,8 @@ void ReloadNewGRFData() AnalyseIndustryTileSpriteGroups(); extern void AnalyseHouseSpriteGroups(); AnalyseHouseSpriteGroups(); - AfterLoadVehicles(false); + AfterLoadVehiclesPhase1(false); + AfterLoadVehiclesPhase2(false); StartupEngines(); GroupStatistics::UpdateAfterLoad(); /* update station graphics */ diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 11413034b4..8a37546990 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -28,7 +28,6 @@ #include "../safeguards.h" -void AfterLoadVehicles(bool part_of_load); bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // From train_cmd.cpp void ReverseTrainDirection(Train *v); void ReverseTrainSwapVeh(Train *v, int l, int r); diff --git a/src/sl/saveload_internal.h b/src/sl/saveload_internal.h index d97a574ba9..fe8baaccac 100644 --- a/src/sl/saveload_internal.h +++ b/src/sl/saveload_internal.h @@ -25,7 +25,8 @@ void MoveBuoysToWaypoints(); void MoveWaypointsToBaseStations(); SaveLoadTable GetBaseStationDescription(); -void AfterLoadVehicles(bool part_of_load); +void AfterLoadVehiclesPhase1(bool part_of_load); +void AfterLoadVehiclesPhase2(bool part_of_load); void AfterLoadVehiclesRemoveAnyFoundInvalid(); void AfterLoadEngines(); void FixupTrainLengths(); diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index 27268c75ea..5e76094215 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -262,13 +262,13 @@ extern uint8_t _age_cargo_skip_counter; // From misc_sl.cpp static std::vector _load_invalid_vehicles_to_delete; -/** Called after load to update coordinates */ -void AfterLoadVehicles(bool part_of_load) +/** Called after load for phase 1 of vehicle initialisation */ +void AfterLoadVehiclesPhase1(bool part_of_load) { _load_invalid_vehicles_to_delete.clear(); const Vehicle *si_v = nullptr; - SCOPE_INFO_FMT([&si_v], "AfterLoadVehicles: %s", scope_dumper().VehicleInfo(si_v)); + SCOPE_INFO_FMT([&si_v], "AfterLoadVehiclesPhase1: %s", scope_dumper().VehicleInfo(si_v)); for (Vehicle *v : Vehicle::Iterate()) { si_v = v; /* Reinstate the previous pointer */ @@ -420,15 +420,6 @@ void AfterLoadVehicles(bool part_of_load) } } - if (SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT) && (_network_server || !_networking)) { - for (Train *t : Train::Iterate()) { - si_v = t; - if (t->IsVirtual() && t->First() == t) { - delete t; - } - } - } - if (IsSavegameVersionBefore(SLV_VEHICLE_ECONOMY_AGE) && SlXvIsFeatureMissing(XSLFI_VEHICLE_ECONOMY_AGE)) { /* Set vehicle economy age based on calendar age. */ for (Vehicle *v : Vehicle::Iterate()) { @@ -439,10 +430,16 @@ void AfterLoadVehicles(bool part_of_load) si_v = nullptr; CheckValidVehicles(); +} +/** Called after load for phase 2 of vehicle initialisation */ +void AfterLoadVehiclesPhase2(bool part_of_load) +{ + const Vehicle *si_v = nullptr; + SCOPE_INFO_FMT([&si_v], "AfterLoadVehiclesPhase2: %s", scope_dumper().VehicleInfo(si_v)); for (Vehicle *v : Vehicle::IterateFrontOnly()) { si_v = v; - assert(v->first != nullptr); + assert(v->First() != nullptr); v->trip_occupancy = CalcPercentVehicleFilled(v, nullptr); @@ -498,6 +495,16 @@ void AfterLoadVehicles(bool part_of_load) } } + if (part_of_load && SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT) && (_network_server || !_networking)) { + for (Train *t : Train::IterateFrontOnly()) { + si_v = t; + if (t->IsVirtual()) { + t->unitnumber = 0; + delete t; + } + } + } + /* Stop non-front engines */ if (part_of_load && IsSavegameVersionBefore(SLV_112)) { for (Vehicle *v : Vehicle::Iterate()) { diff --git a/src/vehicle_base.h b/src/vehicle_base.h index b0fe4bfb46..2a672d8d0b 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -323,7 +323,7 @@ private: public: friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code friend void FixOldVehicles(); - friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the #previous and #first pointers while loading + friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< So we can set the #previous and #first pointers while loading friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading friend upstream_sl::SlVehicleCommon; From 92b6e06ba21e1aab1209e66c65ea34df10ae2941 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 1 Jul 2024 17:02:36 +0100 Subject: [PATCH 038/107] Fix #12832: Sanitise strings from NewGRF before logging them in Debug output. NewGRF strings may not be UTF-8 encoded, which causes issues on Windows. (cherry picked from commit b08e465c8d4df48d42fb603c867a7c756ce18a74) --- src/newgrf.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index a43bb4097a..1dfc6b7824 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2904,14 +2904,14 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, co if (prop == 0x13) { map.openttd_id = lang->GetGenderIndex(name.data()); if (map.openttd_id >= MAX_NUM_GENDERS) { - GrfMsg(1, "GlobalVarChangeInfo: Gender name {} is not known, ignoring", name); + GrfMsg(1, "GlobalVarChangeInfo: Gender name {} is not known, ignoring", StrMakeValid(name)); } else { _cur.grffile->language_map[curidx].gender_map.push_back(map); } } else { map.openttd_id = lang->GetCaseIndex(name.data()); if (map.openttd_id >= MAX_NUM_CASES) { - GrfMsg(1, "GlobalVarChangeInfo: Case name {} is not known, ignoring", name); + GrfMsg(1, "GlobalVarChangeInfo: Case name {} is not known, ignoring", StrMakeValid(name)); } else { _cur.grffile->language_map[curidx].case_map.push_back(map); } @@ -7202,7 +7202,7 @@ static void FeatureNewName(ByteReader *buf) for (; id < endid && buf->HasData(); id++) { const std::string_view name = buf->ReadString(); - GrfMsg(8, "FeatureNewName: 0x{:04X} <- {}", id, name); + GrfMsg(8, "FeatureNewName: 0x{:04X} <- {}", id, StrMakeValid(name)); switch (feature) { case GSF_TRAINS: @@ -7980,7 +7980,7 @@ static void ScanInfo(ByteReader *buf) if (grf_version < 2 || grf_version > 8) { SetBit(_cur.grfconfig->flags, GCF_INVALID); - Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID %08X) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->GetDisplayPath(), name, BSWAP32(grfid), grf_version); + Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID %08X) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->GetDisplayPath(), StrMakeValid(name), BSWAP32(grfid), grf_version); } /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ @@ -8025,7 +8025,7 @@ static void GRFInfo(ByteReader *buf) _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; /* Do swap the GRFID for displaying purposes since people expect that */ - Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, BSWAP32(grfid), name, (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version); + Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, BSWAP32(grfid), StrMakeValid(name), (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version); } /* Action 0x0A */ @@ -8202,7 +8202,7 @@ static void GRFComment(ByteReader *buf) if (!buf->HasData()) return; std::string_view text = buf->ReadString(); - GrfMsg(2, "GRFComment: {}", text); + GrfMsg(2, "GRFComment: {}", StrMakeValid(text)); } /* Action 0x0D (GLS_SAFETYSCAN) */ From ace441d5ea364f434c08f2cd209083f8c1fb5e9d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 2 Jul 2024 18:56:43 +0100 Subject: [PATCH 039/107] Fix GrfMsg logging in ChangeGRFFeatureTestName --- src/newgrf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 1dfc6b7824..0c2934968e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -9509,11 +9509,11 @@ static bool ChangeGRFFeatureTestName(uint8_t langid, std::string_view str) for (const GRFFeatureInfo *info = _grf_feature_list; info->name != nullptr; info++) { if (str == info->name) { _current_grf_feature_test.feature = info; - GrfMsg(2, "Action 14 feature test: found feature named: '{}' (version: %u) in 'FTST'->'NAME'", str, info->version); + GrfMsg(2, "Action 14 feature test: found feature named: '{}' (version: {}) in 'FTST'->'NAME'", StrMakeValid(str), info->version); return true; } } - GrfMsg(2, "Action 14 feature test: could not find feature named: '{}' in 'FTST'->'NAME'", str); + GrfMsg(2, "Action 14 feature test: could not find feature named: '{}' in 'FTST'->'NAME'", StrMakeValid(str)); _current_grf_feature_test.feature = nullptr; return true; } From 3a1f1e12bce0704211248acfb52f1d3e095553b7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 2 Jul 2024 22:20:36 +0100 Subject: [PATCH 040/107] Fix Linux compilation issues in settingsgen --- src/settingsgen/settingsgen.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp index 9522e0ec6a..334347f3de 100644 --- a/src/settingsgen/settingsgen.cpp +++ b/src/settingsgen/settingsgen.cpp @@ -16,6 +16,11 @@ #include +#if !defined(_WIN32) || defined(__CYGWIN__) +#include +#include +#endif + #include "../safeguards.h" /** From 27a847633c16651e8201d2385d962809d0ea7165 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 2 Jul 2024 22:21:40 +0100 Subject: [PATCH 041/107] Version: Committing version data for tag: jgrpp-0.60.0 --- .ottdrev-vc | 4 ++-- README.md | 2 +- jgrpp-changelog.md | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/.ottdrev-vc b/.ottdrev-vc index 50ae389ec8..cee1490b82 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.59.1 20240519 0 5e971bfc026aa9a58773d89c583e78765156b9e4 1 0 2024 -f0d82005ae0e64dc0f833d5cbd6776afb06c9a513cc83119ce8fd0a2e5be097b - +jgrpp-0.60.0 20240702 0 3a1f1e12bce0704211248acfb52f1d3e095553b7 1 0 2024 +4a8cdbde579f3e98b369d79e4d603df92fe118c584a42697ab22de56e04f1e8a - diff --git a/README.md b/README.md index dfb247be54..f105b556a0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.59.1 +## JGR's Patchpack version 0.60.0 This is a collection of features and other modifications applied to [OpenTTD](http://www.openttd.org/). It's a separate version of the game which can be installed and played alongside the standard game, not a loadable mod (NewGRF, script, or so on). diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index d023fd6d9c..4eb129a943 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,40 @@ * * * +### v0.60.0 (2024-07-02) +* Fix incorrect water infrastructure total when changing owner of object on water, and when removing objects on water using a multiple-tile clear. +* Fix vehicle route overlay focus handling in orders window for some drop downs. +* Fix template replacements failing when old trains parts were to be stored in the depot, and this would result in a free wagon chain longer than the maximum train length. +* Fix the link graph refresher creating unnecessary links in some cases when using autorefit with cargo-type load orders. +* Fix crash which could occur when loading old savegames in some cases. +* Fix signal blocks containing no-entry signals not being promoted to PBS. +* Fix handling of reservations when reserving up to a one way tunnel-bridge exit. +* Fix vehicle window showing wrong text for profit last period in wallclock timekeeping mode. +* Fix wrong behaviour of drop downs in the routing restriction window in some special cases. +* Allow sorting by average order occupancy in shared order group mode. +* Allow road vehicle overtaking in road waypoint tiles. +* Allow changing the maximum tunnel length and maximum bridge height settings in network games. +* Clicking on a tunnel to show the vehicles inside is now also implemented for road/tram tunnels. +* Add setting for auto-fill drag signal removal to stop at signals with an attached routing restriction (default on). +* Add button to toggle train purchase window dual pane mode. +* Add console command to merge two companies. +* Orders: + * Fix duplicate order duplicating dispatch schedule assignment. + * Fix not being able to move depot unbunch orders to another depot. + * Preserve wait time/timetabled state when duplicating or moving the target of orders. +* Realistic braking: + * Allow removing reservation boundary signal. + * Add setting to allow track editing to ignore realistic braking restrictions. + * Add setting to uniformly scale the acceleration and braking of trains (when using realistic braking). +* Scheduled dispatch: + * Show scheduled dispatch label in order window. + * Allow naming departure slot tags. +* NewGRF signals: + * Fix display of signal styles which show signals on both sides. + * Fix signal GRFs which check whether the signal is on a tunnel portal. +* Fix crashes which could occur on 32 bit Windows builds, when using an SSE blitter. +* Bump trunk base from commit 88cf99017a26f887230d2c14d057a97bbf077f7c to commit b2218e75d4dea4261c6638579d3e501080b85bdc. + ### v0.59.1 (2024-05-20) * Fix crash when sorting by capacity in autoreplace window. * Fix non-percentage servicing interval when using wallclock mode. From ffaa36c8d23e7045f82aa3e0de34836f5625baaf Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 00:04:55 +0100 Subject: [PATCH 042/107] Command line: Fix -Z option --- src/openttd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openttd.cpp b/src/openttd.cpp index 84840b6d8e..ad88e8835e 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -749,7 +749,8 @@ static std::vector CreateOptions() for (char c : "QXehx") options.push_back({ .type = ODF_NO_VALUE, .id = c, .shortname = c }); /* Non-upstream options */ - for (char c : "KJZ") options.push_back({ .type = ODF_HAS_VALUE, .id = c, .shortname = c }); + for (char c : "KJ") options.push_back({ .type = ODF_HAS_VALUE, .id = c, .shortname = c }); + for (char c : "Z") options.push_back({ .type = ODF_NO_VALUE, .id = c, .shortname = c }); return options; } From 5f34407ce1a5d86c977de751b541b986e1036eee Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 00:19:38 +0100 Subject: [PATCH 043/107] Command line: Fix truncation of help text Use std::string --- src/openttd.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/openttd.cpp b/src/openttd.cpp index ad88e8835e..336a36779c 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -273,12 +273,10 @@ void CDECL ShowInfoF(const char *str, ...) */ static void ShowHelp() { - char buf[8192]; - char *p = buf; + char buf[2048]; - p += seprintf(p, lastof(buf), "OpenTTD %s\n", _openttd_revision); - p = strecpy(p, - "\n" + std::string msg = stdstr_fmt("OpenTTD %s\n", _openttd_revision); + msg += "\n" "\n" "Command line options:\n" " -v drv = Set video driver (see below)\n" @@ -309,46 +307,49 @@ static void ShowHelp() " -Q = Don't scan for/load NewGRF files on startup\n" " -QQ = Disable NewGRF scanning/loading entirely\n" " -Z = Write detailed version information and exit\n" - "\n", - lastof(buf) - ); + "\n"; /* List the graphics packs */ - p = BaseGraphics::GetSetsList(p, lastof(buf)); + BaseGraphics::GetSetsList(buf, lastof(buf)); + msg += buf; /* List the sounds packs */ - p = BaseSounds::GetSetsList(p, lastof(buf)); + BaseSounds::GetSetsList(buf, lastof(buf)); + msg += buf; /* List the music packs */ - p = BaseMusic::GetSetsList(p, lastof(buf)); + BaseMusic::GetSetsList(buf, lastof(buf)); + msg += buf; /* List the drivers */ - p = DriverFactoryBase::GetDriversInfo(p, lastof(buf)); + DriverFactoryBase::GetDriversInfo(buf, lastof(buf)); + msg += buf; /* List the blitters */ - p = BlitterFactory::GetBlittersInfo(p, lastof(buf)); + BlitterFactory::GetBlittersInfo(buf, lastof(buf)); + msg += buf; /* List the debug facilities. */ - p = DumpDebugFacilityNames(p, lastof(buf)); + DumpDebugFacilityNames(buf, lastof(buf)); + msg += buf; /* We need to initialize the AI, so it finds the AIs */ AI::Initialize(); - const std::string ai_list = AI::GetConsoleList(true); - p = strecpy(p, ai_list.c_str(), lastof(buf)); + msg += AI::GetConsoleList(true); AI::Uninitialize(true); /* We need to initialize the GameScript, so it finds the GSs */ Game::Initialize(); - const std::string game_list = Game::GetConsoleList(true); - p = strecpy(p, game_list.c_str(), lastof(buf)); + msg += Game::GetConsoleList(true); Game::Uninitialize(true); /* ShowInfo put output to stderr, but version information should go * to stdout; this is the only exception */ #if !defined(_WIN32) - printf("%s\n", buf); + msg += "\n"; + fputs(msg.c_str(), stdout); #else - ShowInfoI(buf); + ShowInfoI(msg); #endif } From 28c115fc33be3a0075e21b54c2023860ba013994 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 00:25:16 +0100 Subject: [PATCH 044/107] Fix false positive cache check error on MinGW/GCC 10 builds Due to incorrect default operator== on structs with C arrays. See: #709 See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94924 --- src/company_base.h | 12 ++++++------ src/company_gui.cpp | 4 ++-- src/sl/company_sl.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/company_base.h b/src/company_base.h index 7e7ca8ad4e..85905276fd 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -31,12 +31,12 @@ struct CompanyEconomyEntry { }; struct CompanyInfrastructure { - uint32_t road[ROADTYPE_END]; ///< Count of company owned track bits for each road type. - uint32_t signal; ///< Count of company owned signals. - uint32_t rail[RAILTYPE_END]; ///< Count of company owned track bits for each rail type. - uint32_t water; ///< Count of company owned track bits for canals. - uint32_t station; ///< Count of company owned station tiles. - uint32_t airport; ///< Count of company owned airports. + std::array road{}; ///< Count of company owned track bits for each road type. + uint32_t signal{}; ///< Count of company owned signals. + std::array rail{}; ///< Count of company owned track bits for each rail type. + uint32_t water{}; ///< Count of company owned track bits for canals. + uint32_t station{}; ///< Count of company owned station tiles. + uint32_t airport{}; ///< Count of company owned airports. /** Get total sum of all owned track bits. */ uint32_t GetRailTotal() const diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 51a079a518..d9a4f17d2b 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2456,7 +2456,7 @@ struct CompanyWindow : Window int y = r.top; uint rail_pieces = c->infrastructure.signal; - for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pieces += c->infrastructure.rail[i]; + for (uint32_t pieces : c->infrastructure.rail) rail_pieces += pieces; if (rail_pieces != 0) { SetDParam(0, rail_pieces); DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL); @@ -2464,7 +2464,7 @@ struct CompanyWindow : Window } uint road_pieces = 0; - for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i]; + for (uint32_t pieces : c->infrastructure.road) road_pieces += pieces; if (road_pieces != 0) { SetDParam(0, road_pieces); DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD); diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index 2de43fd73a..8360a94508 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -101,7 +101,7 @@ CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32_t face) void AfterLoadCompanyStats() { /* Reset infrastructure statistics to zero. */ - for (Company *c : Company::Iterate()) MemSetT(&c->infrastructure, 0); + for (Company *c : Company::Iterate()) c->infrastructure = {}; /* Collect airport count. */ for (const Station *st : Station::Iterate()) { From 06718b632d7b32322150a45aa9aa42097f3e2f2d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 02:07:39 +0100 Subject: [PATCH 045/107] Fix TCP game packet ID to string mapping --- src/network/core/tcp_game.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index 3e9c6bee53..1c47f12dcf 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -28,14 +28,16 @@ static const char* _packet_game_type_names[] { "SERVER_BANNED", "CLIENT_JOIN", "SERVER_ERROR", - "CLIENT_COMPANY_INFO", - "SERVER_COMPANY_INFO", + "CLIENT_UNUSED", + "SERVER_UNUSED", "SERVER_GAME_INFO", "CLIENT_GAME_INFO", + "SERVER_NEWGAME", + "SERVER_SHUTDOWN", "SERVER_GAME_INFO_EXTENDED", "SERVER_AUTH_REQUEST", "CLIENT_AUTH_RESPONSE", - "SERVER_AUTH_COMPLETED", + "SERVER_ENABLE_ENCRYPTION", "CLIENT_IDENTIFY", "SERVER_CHECK_NEWGRFS", "CLIENT_NEWGRFS_CHECKED", @@ -69,8 +71,6 @@ static const char* _packet_game_type_names[] { "CLIENT_SET_NAME", "SERVER_COMPANY_UPDATE", "SERVER_CONFIG_UPDATE", - "SERVER_NEWGAME", - "SERVER_SHUTDOWN", "CLIENT_QUIT", "SERVER_QUIT", "CLIENT_ERROR", From 7c569b2c83cc473c88961a300b2d28722958aab2 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 02:32:57 +0100 Subject: [PATCH 046/107] Fix PACKET_SERVER_MAP_DONE prepending with packet encryption Also fix logging of sent encrypted packets --- src/network/core/packet.cpp | 24 +++++++++++++++--------- src/network/core/packet.h | 22 +++++++++++++++++++++- src/network/core/tcp.cpp | 7 ++++--- src/network/core/tcp_game.cpp | 2 +- src/network/network_server.cpp | 2 +- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/network/core/packet.cpp b/src/network/core/packet.cpp index 65f2f89a60..f350c431da 100644 --- a/src/network/core/packet.cpp +++ b/src/network/core/packet.cpp @@ -54,12 +54,16 @@ Packet::Packet(NetworkSocketHandler *cs, PacketType type, size_t limit) : pos(0) void Packet::ResetState(PacketType type) { this->buffer.clear(); + this->tx_packet_type = type; /* Allocate space for the the size so we can write that in just before sending the packet. */ size_t size = EncodedLengthOfPacketSize(); if (cs != nullptr && cs->send_encryption_handler != nullptr) { /* Allocate some space for the message authentication code of the encryption. */ size += cs->send_encryption_handler->MACSize(); + this->encyption_pending = true; + } else { + this->encyption_pending = false; } assert(this->CanWriteToPacket(size)); this->buffer.resize(size, 0); @@ -70,7 +74,7 @@ void Packet::ResetState(PacketType type) /** * Writes the packet size from the raw packet from packet->size */ -void Packet::PrepareToSend() +void Packet::PrepareForSendQueue() { /* Prevent this to be called twice and for packets that have been received. */ assert(this->buffer[0] == 0 && this->buffer[1] == 0); @@ -78,17 +82,19 @@ void Packet::PrepareToSend() this->buffer[0] = GB(this->Size(), 0, 8); this->buffer[1] = GB(this->Size(), 8, 8); - if (cs != nullptr && cs->send_encryption_handler != nullptr) { - size_t offset = EncodedLengthOfPacketSize(); - size_t mac_size = cs->send_encryption_handler->MACSize(); - size_t message_offset = offset + mac_size; - cs->send_encryption_handler->Encrypt(std::span(&this->buffer[offset], mac_size), std::span(&this->buffer[message_offset], this->buffer.size() - message_offset)); - } - - this->pos = 0; // We start reading from here + this->pos = 0; // We start reading from here this->buffer.shrink_to_fit(); } +void Packet::PreSendEncryption() +{ + this->encyption_pending = false; + size_t offset = EncodedLengthOfPacketSize(); + size_t mac_size = cs->send_encryption_handler->MACSize(); + size_t message_offset = offset + mac_size; + cs->send_encryption_handler->Encrypt(std::span(&this->buffer[offset], mac_size), std::span(&this->buffer[message_offset], this->buffer.size() - message_offset)); +} + /** * Is it safe to write to the packet, i.e. didn't we run over the buffer? * @param bytes_to_write The amount of bytes we want to try to write. diff --git a/src/network/core/packet.h b/src/network/core/packet.h index 1a8211aaf0..19eb0feaaa 100644 --- a/src/network/core/packet.h +++ b/src/network/core/packet.h @@ -51,6 +51,10 @@ struct Packet : public BufferSerialisationHelper, public BufferDeseriali private: /** The current read/write position in the packet */ PacketSize pos; + /** Whether encryption is required for this packet */ + bool encyption_pending = false; + /** Packet type, for transmitted packets */ + PacketType tx_packet_type; /** The buffer of this packet. */ std::vector buffer; /** The limit for the packet size. */ @@ -59,6 +63,8 @@ private: /** Socket we're associated with. */ NetworkSocketHandler *cs; + void PreSendEncryption(); + public: struct ReadTag{}; Packet(ReadTag tag, NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = EncodedLengthOfPacketSize()); @@ -66,8 +72,21 @@ public: void ResetState(PacketType type); + void PrepareForSendQueue(); + + inline void CheckPendingPreSendEncryption() + { + if (this->encyption_pending) { + this->PreSendEncryption(); + } + } + /* Sending/writing of packets */ - void PrepareToSend(); + inline void PrepareToSend() + { + this->PrepareForSendQueue(); + this->CheckPendingPreSendEncryption(); + } std::vector &GetSerialisationBuffer() { return this->buffer; } size_t GetSerialisationLimit() const { return this->limit; } @@ -88,6 +107,7 @@ public: size_t Size() const; [[nodiscard]] bool PrepareToRead(); PacketType GetPacketType() const; + PacketType GetTransmitPacketType() const { return this->tx_packet_type; } bool CanReadFromPacket(size_t bytes_to_read, bool close_connection = false); diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 7793e2bb1a..e748eb8165 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -69,7 +69,7 @@ void NetworkTCPSocketHandler::SendPacket(std::unique_ptr packet) { assert(packet != nullptr); - packet->PrepareToSend(); + packet->PrepareForSendQueue(); this->packet_queue.push_back(std::move(packet)); } @@ -84,11 +84,11 @@ void NetworkTCPSocketHandler::SendPrependPacket(std::unique_ptr packet, { assert(packet != nullptr); - packet->PrepareToSend(); + packet->PrepareForSendQueue(); if (queue_after_packet_type >= 0) { for (auto iter = this->packet_queue.begin(); iter != this->packet_queue.end(); ++iter) { - if ((*iter)->GetPacketType() == queue_after_packet_type) { + if ((*iter)->GetTransmitPacketType() == queue_after_packet_type) { ++iter; this->packet_queue.insert(iter, std::move(packet)); return; @@ -131,6 +131,7 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) while (!this->packet_queue.empty()) { Packet &p = *this->packet_queue.front(); + p.CheckPendingPreSendEncryption(); ssize_t res = p.TransferOut(send, this->sock, 0); if (res == -1) { NetworkError err = NetworkError::GetLast(); diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index 1c47f12dcf..9573e78ec2 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -295,7 +295,7 @@ std::string NetworkGameSocketHandler::GetDebugInfo() const { return ""; } void NetworkGameSocketHandler::LogSentPacket(const Packet &pkt) { - PacketGameType type = (PacketGameType)pkt.GetPacketType(); + PacketGameType type = (PacketGameType)pkt.GetTransmitPacketType(); DEBUG(net, 5, "[tcp/game] sent packet type %d (%s) to client %d, %s", type, GetPacketGameTypeName(type), this->client_id, this->GetDebugInfo().c_str()); } diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index c4a84de80c..1dca8f30d5 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -136,7 +136,7 @@ struct PacketWriter : SaveFilter { } bool last_packet = false; for (auto &p : this->packets) { - if (p->GetPacketType() == PACKET_SERVER_MAP_DONE) last_packet = true; + if (p->GetTransmitPacketType() == PACKET_SERVER_MAP_DONE) last_packet = true; this->cs->SendPacket(std::move(p)); } From 5dc0bb61ea728d86503d2cb9ea881af6c7f83b94 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 17:52:20 +0100 Subject: [PATCH 047/107] Test: Check that game packet ID to string mappings are correct/complete --- src/network/core/tcp_game.h | 2 +- src/tests/CMakeLists.txt | 1 + src/tests/test_network_debug.cpp | 78 ++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/tests/test_network_debug.cpp diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index fba18de16a..9a63db6446 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -143,7 +143,7 @@ enum PacketGameType : uint8_t { PACKET_END, ///< Must ALWAYS be on the end of this list!! (period) }; -const char *GetPacketTypeName(PacketGameType type); +const char *GetPacketGameTypeName(PacketGameType type); /** Packet that wraps a command */ struct CommandPacket; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index cc6334df69..756a4bf39f 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -11,6 +11,7 @@ add_test_files( strings_func.cpp test_main.cpp test_network_crypto.cpp + test_network_debug.cpp test_script_admin.cpp test_window_desc.cpp ) diff --git a/src/tests/test_network_debug.cpp b/src/tests/test_network_debug.cpp new file mode 100644 index 0000000000..fa6f35193a --- /dev/null +++ b/src/tests/test_network_debug.cpp @@ -0,0 +1,78 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file test_network_debug.cpp Tests for network debug related functions. */ + +#include "../stdafx.h" + +#include "../3rdparty/catch2/catch.hpp" + +#include "../network/core/tcp_game.h" + + +TEST_CASE("GetPacketGameTypeName") +{ + uint number_of_tests = 0; +#define CHECK_NAME(pkttype) number_of_tests++; CHECK(GetPacketGameTypeName(PACKET_ ## pkttype) == std::string_view{#pkttype}) + CHECK_NAME(SERVER_FULL); + CHECK_NAME(SERVER_BANNED); + CHECK_NAME(CLIENT_JOIN); + CHECK_NAME(SERVER_ERROR); + CHECK_NAME(CLIENT_UNUSED); + CHECK_NAME(SERVER_UNUSED); + CHECK_NAME(SERVER_GAME_INFO); + CHECK_NAME(CLIENT_GAME_INFO); + CHECK_NAME(SERVER_NEWGAME); + CHECK_NAME(SERVER_SHUTDOWN); + CHECK_NAME(SERVER_GAME_INFO_EXTENDED); + CHECK_NAME(SERVER_AUTH_REQUEST); + CHECK_NAME(CLIENT_AUTH_RESPONSE); + CHECK_NAME(SERVER_ENABLE_ENCRYPTION); + CHECK_NAME(CLIENT_IDENTIFY); + CHECK_NAME(SERVER_CHECK_NEWGRFS); + CHECK_NAME(CLIENT_NEWGRFS_CHECKED); + CHECK_NAME(SERVER_NEED_COMPANY_PASSWORD); + CHECK_NAME(CLIENT_COMPANY_PASSWORD); + CHECK_NAME(CLIENT_SETTINGS_PASSWORD); + CHECK_NAME(SERVER_SETTINGS_ACCESS); + CHECK_NAME(SERVER_WELCOME); + CHECK_NAME(SERVER_CLIENT_INFO); + CHECK_NAME(CLIENT_GETMAP); + CHECK_NAME(SERVER_WAIT); + CHECK_NAME(SERVER_MAP_BEGIN); + CHECK_NAME(SERVER_MAP_SIZE); + CHECK_NAME(SERVER_MAP_DATA); + CHECK_NAME(SERVER_MAP_DONE); + CHECK_NAME(CLIENT_MAP_OK); + CHECK_NAME(SERVER_JOIN); + CHECK_NAME(SERVER_FRAME); + CHECK_NAME(CLIENT_ACK); + CHECK_NAME(SERVER_SYNC); + CHECK_NAME(CLIENT_COMMAND); + CHECK_NAME(SERVER_COMMAND); + CHECK_NAME(CLIENT_CHAT); + CHECK_NAME(SERVER_CHAT); + CHECK_NAME(SERVER_EXTERNAL_CHAT); + CHECK_NAME(CLIENT_RCON); + CHECK_NAME(SERVER_RCON); + CHECK_NAME(CLIENT_MOVE); + CHECK_NAME(SERVER_MOVE); + CHECK_NAME(CLIENT_SET_PASSWORD); + CHECK_NAME(CLIENT_SET_NAME); + CHECK_NAME(SERVER_COMPANY_UPDATE); + CHECK_NAME(SERVER_CONFIG_UPDATE); + CHECK_NAME(CLIENT_QUIT); + CHECK_NAME(SERVER_QUIT); + CHECK_NAME(CLIENT_ERROR); + CHECK_NAME(SERVER_ERROR_QUIT); + CHECK_NAME(CLIENT_DESYNC_LOG); + CHECK_NAME(SERVER_DESYNC_LOG); + CHECK_NAME(CLIENT_DESYNC_MSG); + CHECK_NAME(CLIENT_DESYNC_SYNC_DATA); +#undef CHECK_NAME + CHECK(number_of_tests == static_cast(PACKET_END)); +} From dcd4295d4ea5266fe898e394762fddf6e2e1402b Mon Sep 17 00:00:00 2001 From: TELK Date: Thu, 4 Jul 2024 02:08:25 +0900 Subject: [PATCH 048/107] Update: Korean translation up to 0.60.0 (#710) --- src/lang/extra/korean.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/lang/extra/korean.txt b/src/lang/extra/korean.txt index 4a0ac4d9fc..9a3f22a584 100644 --- a/src/lang/extra/korean.txt +++ b/src/lang/extra/korean.txt @@ -155,6 +155,13 @@ STR_CONFIG_SETTING_REALISTIC_BRAKING_ASPECT_LIMITED_HELPTEXT :현실적 감 STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION :열차 가속 제한: {STRING} STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION_HELPTEXT :현실적 열차 감속 모델을 사용할 경우, 열차의 최대 가속 또한 제한합니다. 이 설정은 일부 열차에서 지나치게 빠른 가속으로 인해 승객들이 음료수를 흘리는 것을 방지하기 위함입니다. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT :열차 감/가속 배수: {STRING} +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_HELPTEXT :열차의 가속과 감속을 얼마나 조정할지에 대한 백분율 값입니다.{}{}이 설정은 열차의 최대 속력을 변경하지 않고 열차의 가속과 감속을 조절하는데 사용할 수 있습니다. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_VALUE :{COMMA}% + +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING :선로 편집시 현실적 감속 무시: {STRING} +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING_HELPTEXT :현실적 열차 감속 모델을 무시하고 선로를 편집하는 것을 허용합니다. 이 설정을 켜면, 움직이는 열차가 예약산 선로를 수정/제거하는 제한이 사라집니다. 이 경우 비현실적 감속이 발생할 수 있습니다. + STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT :차례로 나눠 실을 때 열차 속력: {STRING} STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT_HELPTEXT :역에서 열차가 화물을 차례로 나눠 실으며 움직일 때 열차의 최대 허용 속력입니다. @@ -761,6 +768,9 @@ STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_ANYWHERE :어디에나 STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS :드래그로 신호기 자동 설치시 역/경유지 무시: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS_HELPTEXT :신호기를 CTRL + 드래그하여 놓을 때의 행동을 선택합니다. 이 설정을 끄면, 신호기는 역/경유지 칸까지만 설치됩니다. 이 설정을 켜면, 역/경유지의 너머까지 신호기가 계속 설치됩니다. +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL :드래그로 신호기를 자동 제거할 때, 경로 제한 신호기 앞에서 제거를 멈추기: {STRING} +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL_HELPTEXT :CTRL+드래그를 이용하여 신호기를 제거할 때의 신호기 설치/제거 행동 방식을 선택합니다. 이 설정을 켜면, 신호기를 제거할 때 경로 제한 프로그램이 있는 신호기 앞에 있는 신호기까지만 제거될 것입니다. + STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED :{WHITE}설정을 변경할 수 없습니다... STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED_NEWGRF :{WHITE}...NewGRF가 사용 중인 설정입니다 @@ -1517,6 +1527,7 @@ STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON :{BLACK}기관 STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON :{BLACK}객화차 이름 지정 STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP :{BLACK}기관차나 동력차의 모델명을 변경합니다 STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP :{BLACK}객화차의 모델명을 변경합니다 +STR_BUY_VEHICLE_TRAIN_TOGGLE_DUAL_PANE_TOOLTIP :{BLACK}기관차와 객화차 따로보기 STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION :{WHITE}기관차의 모델명을 변경합니다 STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION :{WHITE}객화차의 모델명을 변경합니다 @@ -1665,8 +1676,12 @@ STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST :첫 번째 슬 STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST :첫 번째 슬롯이 아닐 때 STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST :마지막 슬롯일 때 STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST :마지막 슬롯이 아닐 때 + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :태그 {0:NUM}{P 0 "이" "가"} 있을 때 +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG_NAMED :태그 {0:NUM}({1:STRING}){P 0 "이" "가"} 있을 때 + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :태그 {0:NUM}{P 0 "이" "가"} 없을 때 +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG_NAMED :태그 {0:NUM}({1:STRING}){P 0 "이" "가"} 없을 때 STR_ORDERS_MANAGE_LIST :{BLACK}목록 관리 STR_ORDERS_MANAGE_LIST_TOOLTIP :{BLACK}이 경로 목록 관리 @@ -1893,6 +1908,7 @@ STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}여기 STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}이 도로 경유지를 제거할 수 없습니다... STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST :{WHITE}도로 경유지를 먼저 제거하십시오 STR_ERROR_UNSUITABLE_SIGNAL_TYPE :{WHITE}... 적절하지 않은 신호기 종류입니다 +STR_ERROR_RESTRICTED_SIGNAL :{WHITE}... 신호기에 경로 제한 프로그램이 있습니다 STR_ERROR_SIGNAL_CHANGES :{WHITE}프로그램 신호기가 한 번에 바꿀 수 있는 제한 횟수를 넘어섰습니다. STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION :{WHITE}여기에 역을 짓기에는 다리가 너무 낮습니다. @@ -2135,10 +2151,16 @@ STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}다른 STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP :{BLACK}다른 차량의 배차 일정을 덧붙입니다. STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS :출발 슬롯 재사용 STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}출발 슬롯을 1번 이상 재사용해도 되는지 여부를 설정합니다. +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG :태그 {NUM} 이름 바꾸기 +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_NAMED :태그 {NUM} 이름 바꾸기: {STRING} +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP :{BLACK}출발 슬롯 태그 이름 바꾸기 (조건부 경로에 사용) +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_CAPTION :{BLACK}출발 슬롯 태그 이름 바꾸기 +STR_ERROR_CAN_T_RENAME_DEPARTURE_TAG :{WHITE}출발 슬롯 태그의 이름을 바꿀 수 없습니다... STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}슬롯 관리 STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT :출발 슬롯 재사용 STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP :{BLACK}선택한 출발 슬롯을 1번 이상 재사용해도 되는지 여부를 설정합니다. STR_SCHDISPATCH_TAG_DEPARTURE :태그 {NUM} +STR_SCHDISPATCH_TAG_DEPARTURE_NAMED :태그 {NUM}: {STRING} STR_SCHDISPATCH_TAG_DEPARTURE_TOOLTIP :{BLACK}(조건부 경로에 사용하기 위해) 선택한 출발 슬롯에 태그를 붙입니다. STR_SCHDISPATCH_NO_SCHEDULES :{BLACK}일정 없음 STR_SCHDISPATCH_SCHEDULE_ID :{BLACK}일정 {NUM}/{NUM} @@ -2155,6 +2177,7 @@ STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}다음 이용 STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE :{}출발 슬롯을 1번 이상 재사용 가능함 STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({TT_TIME}) STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}태그 {NUM} +STR_SCHDISPATCH_SLOT_TOOLTIP_TAG_NAMED :{}태그 {NUM}: {STRING} STR_SCHDISPATCH_SUMMARY_NO_LAST_DEPARTURE :{BLACK}이전 출발이 없습니다. STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}최근 출발: {TT_TIME} From ae516b4a869540072f86a8e041f2e2c554dd6670 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 22:04:39 +0100 Subject: [PATCH 049/107] Fix text truncation in Win32 help dialog --- src/os/windows/win32.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 986d1fd0a1..7ecc6540b3 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -301,31 +301,34 @@ void CreateConsole() } /** Temporary pointer to get the help message to the window */ -static const char *_help_msg; +static std::string_view _help_msg; /** Callback function to handle the window */ static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM) { switch (msg) { case WM_INITDIALOG: { - char help_msg[8192]; - const char *p = _help_msg; - char *q = help_msg; - while (q != lastof(help_msg) && *p != '\0') { - if (*p == '\n') { + const size_t help_msg_size = 1 + _help_msg.size() + std::count(_help_msg.begin(), _help_msg.end(), '\n'); + auto help_msg = std::make_unique(help_msg_size); + char *q = help_msg.get(); + char *last = q + help_msg_size - 1; + for (char c : _help_msg) { + if (q == last) break; + if (c == '\n') { *q++ = '\r'; - if (q == lastof(help_msg)) { + if (q == last) { q[-1] = '\0'; break; } } - *q++ = *p++; + *q++ = c; } - *q = '\0'; + *q++ = '\0'; /* We need to put the text in a separate buffer because the default * buffer in OTTD2FS might not be large enough (512 chars). */ - wchar_t help_msg_buf[8192]; - SetDlgItemText(wnd, 11, convert_to_fs(help_msg, help_msg_buf, lengthof(help_msg_buf))); + const size_t help_msg_buf_size = ((q - help_msg.get()) * 3) / 2; + auto help_msg_buf = std::make_unique(help_msg_buf_size); + SetDlgItemText(wnd, 11, convert_to_fs(help_msg.get(), help_msg_buf.get(), help_msg_buf_size)); SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE); } return TRUE; From b3e20ec9b69c7701fc42c5766d644031b78720f7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 3 Jul 2024 22:12:02 +0100 Subject: [PATCH 050/107] Version: Committing version data for tag: jgrpp-0.60.1 --- .ottdrev-vc | 4 ++-- README.md | 2 +- jgrpp-changelog.md | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.ottdrev-vc b/.ottdrev-vc index cee1490b82..28531ff991 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.60.0 20240702 0 3a1f1e12bce0704211248acfb52f1d3e095553b7 1 0 2024 -4a8cdbde579f3e98b369d79e4d603df92fe118c584a42697ab22de56e04f1e8a - +jgrpp-0.60.1 20240703 0 ae516b4a869540072f86a8e041f2e2c554dd6670 1 0 2024 +30d60a49e07e9aa22f4c182f47fdf4d70392c7bafbbaf34c24461486d0d993f2 - diff --git a/README.md b/README.md index f105b556a0..55827fb645 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.60.0 +## JGR's Patchpack version 0.60.1 This is a collection of features and other modifications applied to [OpenTTD](http://www.openttd.org/). It's a separate version of the game which can be installed and played alongside the standard game, not a loadable mod (NewGRF, script, or so on). diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index 4eb129a943..c86824335f 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,12 @@ * * * +### v0.60.1 (2024-07-03) +* Fix network clients being disconnected when attempting to join a multiplayer game. +* Fix false-positive warning messages about inconsistencies which could cause multiplayer desyncs. +* Fix -Z (version info) command line option. +* Fix command line help text being truncated. + ### v0.60.0 (2024-07-02) * Fix incorrect water infrastructure total when changing owner of object on water, and when removing objects on water using a multiple-tile clear. * Fix vehicle route overlay focus handling in orders window for some drop downs. From 2d6c9c2f90de99e7fa783d70304e62895f750574 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Fri, 5 Jul 2024 22:42:34 +0100 Subject: [PATCH 051/107] Fix 05915b21: One-way behaviour of signalled bridge exit applied to bypassing track --- src/train_cmd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index af16cc7e8e..336314130c 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -5754,7 +5754,8 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } goto reverse_train_direction; } else if (!(v->track & TRACK_BIT_WORMHOLE) && IsTunnelBridgeWithSignalSimulation(gp.new_tile) && - IsTunnelBridgeSignalSimulationExitOnly(gp.new_tile) && v->force_proceed == TFP_NONE) { + IsTunnelBridgeSignalSimulationExitOnly(gp.new_tile) && TrackdirEntersTunnelBridge(gp.new_tile, FindFirstTrackdir(trackdirbits)) && + v->force_proceed == TFP_NONE) { goto reverse_train_direction; } else { TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false); From 3fd71b282166e0631aee168c7affc4c9316d9c0e Mon Sep 17 00:00:00 2001 From: Qwest8K Date: Fri, 5 Jul 2024 17:28:49 +0300 Subject: [PATCH 052/107] Update russian.txt --- src/lang/extra/russian.txt | 48 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/lang/extra/russian.txt b/src/lang/extra/russian.txt index 4b6734fccc..45421d276c 100644 --- a/src/lang/extra/russian.txt +++ b/src/lang/extra/russian.txt @@ -1,6 +1,6 @@ STR_CONFIG_SETTING_TREE_PLACER_PERFECT :Превосходный -STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT_EXTRA :{STRING}, 'Превосходный' улучшает распределение и группировку +STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT_EXTRA :{STRING} «Превосходный» улучшает распределение и группировку STR_FINANCES_SECTION_INFRASTRUCTURE_COSTS :{GOLD}Совместное использование инфраструктуры STR_FINANCES_SECTION_INFRASTRUCTURE_INCOME :{GOLD}Совместное использование инфраструктуры @@ -15,14 +15,14 @@ STR_CONFIG_SETTING_ZOOM_LVL_OUT_128X :128x STR_CONFIG_SETTING_DEFAULT_ROAD_TYPE_DEFAULT :По умолчанию -STR_ORDER_CONDITIONAL_CARGO_WAITING :Ждущий груз +STR_ORDER_CONDITIONAL_CARGO_WAITING :Доступный груз STR_ORDER_CONDITIONAL_ACCEPTANCE_DROPDOWN :Принятый груз STR_ORDER_CONDITIONAL_FREE_PLATFORMS :Свободные платформы STR_ORDER_CONDITIONAL_PERCENT :Процент случаев STR_ORDER_CONDITIONAL_SLOT_OCCUPANCY :Заполненность слотов STR_ORDER_CONDITIONAL_TRAIN_IN_SLOT :Поезд в слоте STR_ORDER_CONDITIONAL_CARGO_LOAD_PERCENTAGE :Процент загрузки груза -STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT :Количество ожидающих грузов +STR_ORDER_CONDITIONAL_CARGO_WAITING_AMOUNT :Количество доступного груза STR_ORDER_CONDITIONAL_COUNTER_VALUE :Значение счётчика STR_ORDER_CONDITIONAL_TIME_DATE_VALUE :Текущее время/дата STR_ORDER_CONDITIONAL_TIMETABLE_STATE :Состояние расписания @@ -30,17 +30,17 @@ STR_ORDER_CONDITIONAL_DISPATCH_SLOT :Диспетч STR_ORDER_STOP_LOCATION_THROUGH :[через нагрузку] -STR_CONFIG_SETTING_TOWN_GROWTH_EXTREME_SLOW :Крайне низкая -STR_CONFIG_SETTING_TOWN_GROWTH_VERY_SLOW :Очень низкая +STR_CONFIG_SETTING_TOWN_GROWTH_EXTREME_SLOW :крайне низкая +STR_CONFIG_SETTING_TOWN_GROWTH_VERY_SLOW :очень низкая STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_MINUTES_CUSTOM :Каждые {COMMA}{NBSP}минут{P 0 а ы ""} STR_RIVERS_VERY_MANY :{RED}Очень большое STR_RIVERS_EXTREMELY_MANY :{RED}Крайне большое -STR_CONFIG_SETTING_BRIBE_HELPTEXT_PERIODS :Разрешите компаниям попробовать подкупить местные городские власти. Если взятка будет замечена инспектором, компания не сможет действовать в городе в течение полугода +STR_CONFIG_SETTING_BRIBE_HELPTEXT_PERIODS :Разрешить компаниям подкупать городскую администрацию. Если взятка будет замечена инспектором, компания не сможет действовать в городе в течение полугода. -STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT_PERIODS :Если компания покупает эксклюзивные права на перевозку в городе, станции соперников (пассажирские и грузовые) не будут получать грузы в течение одного периода +STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT_PERIODS :Если компания покупает эксклюзивные права на перевозку в городе, станции соперников (пассажирские и грузовые) не будут получать грузы в течение одного периода. STR_COMMA_SEPARATOR :,{SP} @@ -155,6 +155,13 @@ STR_CONFIG_SETTING_REALISTIC_BRAKING_ASPECT_LIMITED_HELPTEXT :При реал STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION :Ограничение ускорения поезда: {STRING} STR_CONFIG_SETTING_LIMIT_TRAIN_ACCELERATION_HELPTEXT :При использовании реалистичной модели торможения поездов также ограничьте максимальное ускорение поездов. Это необходимо для того, чтобы пассажиры не пролили свои напитки из-за чрезмерно быстрого ускорения некоторых типов поездов. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT :Коэффициент масштабирования ускорения/торможения поезда: {STRING} +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_HELPTEXT :Процент, на который регулируется ускорение и торможение поезда.{}{}Эта настройка может использоваться для изменения ускорения и торможения поездов без изменения их максимальной скорости. +STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_VALUE :{COMMA}% + +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING :Редактирование путей игнорирует реалистичное торможение: {STRING} +STR_CONFIG_SETTING_TRACK_EDIT_IGNORE_REALISTIC_BRAKING_HELPTEXT :Разрешить редактировать пути, игнорируя реалистичную модель торможения поезда. Если включено, ограничения на редактирование/снятие резервирования движущихся поездов не применяются. Это может привести к нереалистичному поведению поезда при торможении. + STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT :Максимальная скорость поездов при сквозной погрузе: {STRING} STR_CONFIG_SETTING_THROUGH_LOAD_SPEED_LIMIT_HELPTEXT :Максимальная разрешенная скорость движения поездов при сквозной погрузке на станции @@ -176,7 +183,7 @@ STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE :Корабли STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE_HELPTEXT :Если включено, то корабли будут пытаться не проходить через друг друга. Наилучшие результаты достигаются при запрете поворотов на 90°. STR_CONFIG_SETTING_CHUNNEL :Разрешить строительство туннелей под водой: {STRING} -STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :Если включено, то туннели можно будет прокладывать под водоемами на уровне моря. На каждом конце туннеля зазор между туннелем и береговой клеткой должен составлять {NUM} и {NUM} клеток. +STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :Если включено, то туннели можно будет прокладывать под водоёмами на уровне моря. На каждом конце туннеля зазор между туннелем и береговой клеткой должен составлять {NUM} и {NUM} клеток. STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY :Поезда разных компаний не смогут врезаться друг в друга: {STRING} STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY_HELPTEXT :Эта настройка предназначена в первую очередь для того, чтобы игроки намеренно не вызывали крушения поездов других компаний в многопользовательских играх с совместным использованием железнодорожной инфраструктуры. @@ -761,6 +768,9 @@ STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_ANYWHERE :Где угод STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS :При перетаскивании автозаполнения продолжать движение мимо станций/маршрутных точек: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS_HELPTEXT :Выберите поведение размещения светофоров при Ctrl+перетаскивание светофоров. Если отключено, то размещение светофора прекращается при достижении станции/маршрутной точки. Если включено, то размещение светофоров продолжается на дальней стороне железнодорожных станций/маршрутных точек. +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL :При удалении сигналов с помощью автозаполнения останавливаться на запрещённых сигналах: {STRING} +STR_CONFIG_SETTING_DRAG_SIGNALS_STOP_RESTRICTED_SIGNAL_HELPTEXT :Выберите поведение размещения сигнала при удалении сигнала с помощью Ctrl+перетаскивание. Если включено, то удаление сигналов прекращается при достижении сигнала с установленной программой ограничения маршрутизации. + STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED :{WHITE}Невозможно изменить настройку... STR_CONFIG_SETTING_NETWORK_CHANGE_NOT_ALLOWED_NEWGRF :{WHITE}...ею управляет NewGRF @@ -1225,8 +1235,8 @@ STR_SELECT_TOWN_LIST_ITEM :{BLACK}{TOWN} STR_TREES_REMOVE_TREES_BUTTON :{BLACK}Удалить все деревья STR_TREES_REMOVE_TREES_TOOLTIP :{BLACK}Удалить все деревья над ландшафтом -STR_TERRAFORM_PUBLIC_ROADS :{BLACK}Строить общественные дороги -STR_TERRAFORM_PUBLIC_ROADS_TOOLTIP :{BLACK}Создайте общественные дороги между городами на карте +STR_TERRAFORM_PUBLIC_ROADS :{BLACK}Построить общественные дороги +STR_TERRAFORM_PUBLIC_ROADS_TOOLTIP :{BLACK}Создать общественные дороги между городами на карте STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_ALL :Все предпрятия @@ -1666,8 +1676,12 @@ STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_FIRST :первый с STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_FIRST :не первый слот STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_LAST :последний слот STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_IS_NOT_LAST :не последний слот + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG :имеет метку {NUM} +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_HAS_TAG_NAMED :имеет метку {NUM} ({STRING}) + STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG :не имеет метку {NUM} +STR_ORDER_CONDITIONAL_COMPARATOR_DISPATCH_SLOT_DOESNT_HAVE_TAG_NAMED :не имеет метку {NUM} ({STRING}) STR_ORDERS_MANAGE_LIST :{BLACK}Управление списком STR_ORDERS_MANAGE_LIST_TOOLTIP :{BLACK}Управление списком заданий @@ -1889,12 +1903,13 @@ STR_ERROR_BUILDING_IS_TOO_OLD :{WHITE}... зд STR_ERROR_BUILDING_IS_TOO_MODERN :{WHITE}... здание слишком современное. STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN :{WHITE}... в городе разрешено только одно здание такого типа. STR_ERROR_NO_MORE_BUILDINGS_ALLOWED_PER_TOWN :{WHITE}... слишком много зданий такого типа в городе. -STR_ERROR_BUILDING_NOT_ALLOWED :{WHITE}... здание не разрешается. +STR_ERROR_BUILDING_NOT_ALLOWED :{WHITE}... здание не разрешено. STR_ERROR_TOO_MANY_DOCKS :{WHITE}Слишком много доков STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}Невозможно построить здесь дорожную маршрутную точку... STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}Невозможно удалить дорожную маршрутную точку здесь... STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST :{WHITE}Сначала необходимо удалить дорожную маршрутную точку STR_ERROR_UNSUITABLE_SIGNAL_TYPE :{WHITE}... неподходящий тип сигнала +STR_ERROR_RESTRICTED_SIGNAL :{WHITE}... сигнал прикреплён программу ограничения маршрутизации STR_ERROR_SIGNAL_CHANGES :{WHITE}Превышен предел количество программируемых пресигналов STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION :{WHITE}Мост слишком низкий для станции @@ -2023,7 +2038,7 @@ STR_TMPL_RPL_STOP :{BLACK}Прек STR_TMPL_RPL_STOP_TOOLTIP :{BLACK}Нажмите, чтобы остановить замену поездов в выбранной группе STR_TMPL_TEMPLATE_OVR_VALUE :{BLACK}Стоимость приобретения: {GOLD}{CURRENCY_LONG} STR_TMPL_TEMPLATE_OVR_VALUE_LTBLUE :{BLACK}Стоимость приобретения: {LTBLUE}{CURRENCY_LONG} -STR_TMPL_TEMPLATE_OVR_RUNNING_COST :{BLACK}Расчетные эксплуатационные расходы: {LTBLUE}{CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_RUNNING_COST :{BLACK}Предполагаемые расходы на эксплуатацию: {LTBLUE}{CURRENCY_LONG} STR_TMPL_TEMPLATE_OVR_MULTIPLE :{BLACK}{STRING}{BLACK} {STRING} STR_TMPL_WARNING_FREE_WAGON :{RED}Свободная цепь: не запускается! STR_TMPL_WARNING_VEH_UNAVAILABLE :{RED}Поезд нельзя строить: транспортное средство недоступно! @@ -2137,10 +2152,16 @@ STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES :{BLACK}Доба STR_SCHDISPATCH_APPEND_VEHICLE_SCHEDULES_TOOLTIP :{BLACK}Добавить расписания отправлений с другого транспорта. STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS :Повторное использование слотов отправления STR_SCHDISPATCH_REUSE_DEPARTURE_SLOTS_TOOLTIP :{BLACK}Установить, можно ли использовать слоты отправления более одного раза. +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG :Переименовать метку {NUM} +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_NAMED :Переименовать метку {NUM}: {STRING} +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_TOOLTIP :{BLACK}Переименовать метки слота отправления (для использования с условными заданиями) +STR_SCHDISPATCH_RENAME_DEPARTURE_TAG_CAPTION :{BLACK}Назвать метку слота отправления +STR_ERROR_CAN_T_RENAME_DEPARTURE_TAG :{WHITE}Невозможно назвать метку отправления... STR_SCHDISPATCH_MANAGE_SLOT :{BLACK}Управление слотом STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT :Повторное использование слота отправления STR_SCHDISPATCH_REUSE_THIS_DEPARTURE_SLOT_TOOLTIP :{BLACK}Установить, может ли выбранный слот отправления использоваться более одного раза. STR_SCHDISPATCH_TAG_DEPARTURE :Метка {NUM} +STR_SCHDISPATCH_TAG_DEPARTURE_NAMED :Метка {NUM}: {STRING} STR_SCHDISPATCH_TAG_DEPARTURE_TOOLTIP :{BLACK}Отметить выбранный слот отправления (для использования с условными заказами). STR_SCHDISPATCH_NO_SCHEDULES :{BLACK}Нет расписаний STR_SCHDISPATCH_SCHEDULE_ID :{BLACK}Расписание {NUM} для {NUM} @@ -2157,6 +2178,7 @@ STR_SCHDISPATCH_SLOT_TOOLTIP_NEXT :{}Следую STR_SCHDISPATCH_SLOT_TOOLTIP_REUSE :{}Слот отправления может быть использован более одного раза STR_SCHDISPATCH_SLOT_TOOLTIP_TIME_SUFFIX : ({TT_TIME}) STR_SCHDISPATCH_SLOT_TOOLTIP_TAG :{}Метка {NUM} +STR_SCHDISPATCH_SLOT_TOOLTIP_TAG_NAMED :{}Метка {NUM}: {STRING} STR_SCHDISPATCH_SUMMARY_NO_LAST_DEPARTURE :{BLACK}Предыдущих отправлений нет. STR_SCHDISPATCH_SUMMARY_LAST_DEPARTURE_PAST :{BLACK}Последнее отправление в {TT_TIME}. @@ -2213,7 +2235,7 @@ STR_REFIT_SHIP_PART_DROPDOWN_TOOLTIP :{BLACK}Выбе STR_REFIT_WHOLE_SHIP :Весь корабль STR_REFIT_SHIP_PART :Часть {NUM} -STR_VERY_REDUCED :Очень сниженная +STR_VERY_REDUCED :очень сниженная STR_STATION_VIEW_RENAME_TOOLTIP_EXTRA :{BLACK}{STRING}{}(Ctrl+клик "{STRING}" чтобы сгенерировать новое имя по умолчанию).{}{}Ctrl+клик - обменяться названиями с другой станцией. STR_ERROR_CAN_T_EXCHANGE_STATION_NAMES :{WHITE}Невозможно обменяться названиями станций... From 18ef0741e7d5243000da5eb62e29154ee27d9875 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 6 Jul 2024 13:18:59 +0100 Subject: [PATCH 053/107] Use hash map instead of btree for SpritePointerHolder cache --- src/spritecache.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spritecache.h b/src/spritecache.h index 32ce13418f..84ce4b9417 100644 --- a/src/spritecache.h +++ b/src/spritecache.h @@ -13,7 +13,7 @@ #include "gfx_type.h" #include "zoom_type.h" #include "spriteloader/spriteloader.hpp" -#include "3rdparty/cpp-btree/btree_map.h" +#include "3rdparty/robin_hood/robin_hood.h" /** Data structure describing a sprite. */ struct Sprite { @@ -82,7 +82,7 @@ uint32_t GetSpriteMainColour(SpriteID sprite_id, PaletteID palette_id); struct SpritePointerHolder { private: - btree::btree_map cache; + robin_hood::unordered_map cache; public: inline const Sprite *GetSprite(SpriteID sprite, SpriteType type) const From 61b39296e13fbe6dc9d1f5075534713189bbe15e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 6 Jul 2024 13:34:44 +0100 Subject: [PATCH 054/107] Fix crash when replacing recolour sprite with normal sprite See: #712 --- src/spritecache.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/spritecache.cpp b/src/spritecache.cpp index a869171f6f..6d9c720beb 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -752,14 +752,13 @@ bool LoadNextSprite(int load_index, SpriteFile &file, uint file_sprite_id) } SpriteCache *sc = AllocateSpriteCache(load_index); + sc->Clear(); // Clear existing entry before changing type field sc->file = &file; sc->file_pos = file_pos; sc->SetType(type); if (data != nullptr) { assert(data == _last_sprite_allocation.GetPtr()); sc->Assign(std::move(_last_sprite_allocation)); - } else { - sc->Clear(); } sc->id = file_sprite_id; sc->count = count; From 21793af8dd7f6ac5bb28155928b58cc80b55be64 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 6 Jul 2024 16:41:15 +0100 Subject: [PATCH 055/107] Fix accel/braking percentage setting changes not updating running trains --- src/table/settings/game_settings.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/src/table/settings/game_settings.ini b/src/table/settings/game_settings.ini index d1d6751fce..77b4488fc7 100644 --- a/src/table/settings/game_settings.ini +++ b/src/table/settings/game_settings.ini @@ -337,6 +337,7 @@ max = 200 str = STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT strhelp = STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_HELPTEXT strval = STR_CONFIG_SETTING_TRAIN_ACC_BRAKING_PERCENT_VALUE +post_cb = TrainAccelerationModelChanged cat = SC_EXPERT [SDT_VAR] From 95245d5a572034b617799bf1f124ae777061589f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 6 Jul 2024 18:45:41 +0100 Subject: [PATCH 056/107] Fix crash opening landscape window when there are no available objects See: #713 --- src/newgrf_class_func.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/newgrf_class_func.h b/src/newgrf_class_func.h index e4294b07d2..6142459dbc 100644 --- a/src/newgrf_class_func.h +++ b/src/newgrf_class_func.h @@ -120,8 +120,8 @@ uint NewGRFClass::GetUIClassCount() template bool NewGRFClass::HasUIClass() { - for (uint i = 0; i < Tmax && classes[i].global_id != 0; i++) { - if (classes[i].GetUISpecCount() > 0) return true; + for (const auto &cls : NewGRFClass::classes) { + if (cls.GetUISpecCount() > 0) return true; } return false; } From 0dc4be2aa0c0e2d8823949371b5373f25ab4eb48 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 7 Jul 2024 15:00:50 +0100 Subject: [PATCH 057/107] Fix minor code style issue --- src/sl/saveload.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 96ffef71d8..329984e556 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2588,7 +2588,7 @@ static void SlLoadCheckChunk(const ChunkHandler *ch, uint32_t chunk_id) if (ext_flags) { SlErrorCorruptFmt("CH_ARRAY does not take chunk header extension flags: 0x%X in %s", ext_flags, ChunkIDDumper()(chunk_id)); } - if (ch && ch->load_check_proc) { + if (ch != nullptr && ch->load_check_proc) { ch->load_check_proc(); } else { if (m == CH_TABLE) SlSkipTableHeader(); @@ -2600,7 +2600,7 @@ static void SlLoadCheckChunk(const ChunkHandler *ch, uint32_t chunk_id) if (ext_flags) { SlErrorCorruptFmt("CH_SPARSE_ARRAY does not take chunk header extension flags: 0x%X in %s", ext_flags, ChunkIDDumper()(chunk_id)); } - if (ch && ch->load_check_proc) { + if (ch != nullptr && ch->load_check_proc) { ch->load_check_proc(); } else { if (m == CH_SPARSE_TABLE) SlSkipTableHeader(); @@ -2632,7 +2632,7 @@ static void SlLoadCheckChunk(const ChunkHandler *ch, uint32_t chunk_id) } _sl.obj_len = len; endoffs = _sl.reader->GetSize() + len; - if (ch && ch->load_check_proc) { + if (ch != nullptr && ch->load_check_proc) { ch->load_check_proc(); } else { SlSkipBytes(len); From 61f920138f421b4e4a498890c2220cad6e25e651 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 7 Jul 2024 15:34:09 +0100 Subject: [PATCH 058/107] Saveload: Add helper to skip chunk contents --- src/sl/saveload.cpp | 11 +++++++++++ src/sl/saveload.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 329984e556..8994b5f33e 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2332,6 +2332,17 @@ void SlLoadTableWithArrayLengthPrefixesMissing() SetBit(_sl.block_flags, SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING); } +void SlSkipChunkContents() +{ + if (SlIsTableChunk()) SlSkipTableHeader(); + + if (_sl.block_mode == CH_RIFF) { + SlSkipBytes(SlGetFieldLength()); + } else { + SlSkipArray(); + } +} + /** * Save or Load (a list of) global variables. * @param slt The SaveLoad table with objects to save/load. diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 10795c8be0..31e8a02d97 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1079,6 +1079,8 @@ void SlSaveTableObjectChunk(const SaveLoadTable &slt); void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); void SlLoadTableWithArrayLengthPrefixesMissing(); +void SlSkipChunkContents(); + inline void SlSaveTableObjectChunk(const NamedSaveLoadTable &slt) { SlSaveTableObjectChunk(SlTableHeader(slt)); From d6b3ba60457afc32cf91d0f9da3c1523d11d642f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 7 Jul 2024 15:43:31 +0100 Subject: [PATCH 059/107] Saveload: Use table format for debug info No longer add wrapper text around config --- src/sl/debug_sl.cpp | 77 ++++++++++++++++++++++++-------------- src/sl/extended_ver_sl.cpp | 2 +- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/sl/debug_sl.cpp b/src/sl/debug_sl.cpp index 7a474d34c8..0a8df9d242 100644 --- a/src/sl/debug_sl.cpp +++ b/src/sl/debug_sl.cpp @@ -17,17 +17,6 @@ #include "../safeguards.h" -static void Save_DBGL() -{ - if (_savegame_DBGL_data != nullptr) { - size_t length = strlen(_savegame_DBGL_data); - SlSetLength(length); - MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast(_savegame_DBGL_data), length); - } else { - SlSetLength(0); - } -} - static void Load_DBGL() { size_t length = SlGetFieldLength(); @@ -50,21 +39,6 @@ static void Check_DBGL() } } -static void Save_DBGC() -{ - extern std::string _config_file_text; - const char header[] = "*** openttd.cfg start ***\n"; - const char footer[] = "*** openttd.cfg end ***\n"; - if (_save_DBGC_data) { - SlSetLength(lengthof(header) + _config_file_text.size() + lengthof(footer) - 2); - MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast(header), lengthof(header) - 1); - MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast(_config_file_text.data()), _config_file_text.size()); - MemoryDumper::GetCurrent()->CopyBytes(reinterpret_cast(footer), lengthof(footer) - 1); - } else { - SlSetLength(0); - } -} - static void Load_DBGC() { size_t length = SlGetFieldLength(); @@ -87,9 +61,56 @@ static void Check_DBGC() } } +static void Save_DBGD() +{ + if (!SlIsTableChunk()) { + SlSkipChunkContents(); + return; + } + + std::vector nsl; + if (_save_DBGC_data) { + extern std::string _config_file_text; + nsl.push_back(NSLT("config", SLEG_SSTR(_config_file_text, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE))); + } + if (_savegame_DBGL_data != nullptr) { + nsl.push_back(NSLT("log", SLEG_STR(_savegame_DBGL_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE))); + } + SlSaveTableObjectChunk(nsl); +} + +static void Load_DBGD() +{ + if (!SlIsTableChunk()) { + SlSkipChunkContents(); + return; + } + + static const NamedSaveLoad nsl[] = { + NSLT("config", SLEG_SSTR(_loadgame_DBGC_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), + NSLT("log", SLEG_SSTR(_loadgame_DBGL_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), + }; + SlLoadTableOrRiffFiltered(nsl); +} + +static void Check_DBGD() +{ + if (!SlIsTableChunk() || !_load_check_data.want_debug_data) { + SlSkipChunkContents(); + return; + } + + static const NamedSaveLoad nsl[] = { + NSLT("config", SLEG_SSTR(_load_check_data.debug_config_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), + NSLT("log", SLEG_SSTR(_load_check_data.debug_log_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), + }; + SlLoadTableOrRiffFiltered(nsl); +} + extern const ChunkHandler debug_chunk_handlers[] = { - { 'DBGL', Save_DBGL, Load_DBGL, nullptr, Check_DBGL, CH_RIFF }, - { 'DBGC', Save_DBGC, Load_DBGC, nullptr, Check_DBGC, CH_RIFF }, + { 'DBGL', nullptr, Load_DBGL, nullptr, Check_DBGL, CH_UNUSED }, + { 'DBGC', nullptr, Load_DBGC, nullptr, Check_DBGC, CH_UNUSED }, + { 'DBGD', Save_DBGD, Load_DBGD, nullptr, Check_DBGD, CH_TABLE }, }; extern const ChunkHandlerTable _debug_chunk_handlers(debug_chunk_handlers); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index f0c3dce00c..79041c07a4 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -138,7 +138,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr }, { XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 0, 1, "town_cargo_matrix", nullptr, nullptr, nullptr }, { XSLFI_STATE_CHECKSUM, XSCF_NULL, 1, 1, "state_checksum", nullptr, nullptr, nullptr }, - { XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL,DBGC" }, + { XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 2, 2, "debug", nullptr, nullptr, "DBGD" }, { XSLFI_FLOW_STAT_FLAGS, XSCF_NULL, 1, 1, "flow_stat_flags", nullptr, nullptr, nullptr }, { XSLFI_SPEED_RESTRICTION, XSCF_NULL, 1, 1, "speed_restriction", nullptr, nullptr, "VESR" }, { XSLFI_STATION_GOODS_EXTRA, XSCF_NULL, 1, 1, "station_goods_extra", nullptr, nullptr, nullptr }, From 724c6800c9ff1c3c0980c13f6956c650a92e1038 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 17:50:37 +0100 Subject: [PATCH 060/107] Saveload: Fix table chunk array type length headers --- src/sl/saveload.cpp | 55 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 8994b5f33e..5105013099 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -1532,6 +1532,33 @@ void SlSaveLoadRef(void *ptr, VarType conv) } } +static uint SlGetListTypeLengthSize(size_t size) +{ + if (SlIsTableChunk()) { + return SlGetArrayLength(size); + } else { + return 4; + } +} + +static void SlWriteListLength(size_t size) +{ + if (SlIsTableChunk()) { + SlWriteArrayLength(size); + } else { + SlWriteUint32(static_cast(size)); + } +} + +static size_t SlReadListLength() +{ + if (SlIsTableChunk()) { + return SlReadArrayLength(); + } else { + return IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : SlReadUint32(); + } +} + /** * Template class to help with list-like types. */ @@ -1551,7 +1578,7 @@ public: const SlStorageT *list = static_cast(storage); - int type_size = SlCalcConvFileLen(SLE_FILE_U32); // Size of the length of the list. + int type_size = SlGetListTypeLengthSize(list->size()); // Size of the length of the list. int item_size = SlCalcConvFileLen(cmd == SL_VAR ? conv : (VarType)SLE_FILE_U32); return list->size() * item_size + type_size; } @@ -1580,7 +1607,7 @@ public: switch (_sl.action) { case SLA_SAVE: - SlWriteUint32((uint32_t)list->size()); + SlWriteListLength(list->size()); for (auto &item : *list) { SlSaveLoadMember(cmd, &item, conv); @@ -1591,8 +1618,8 @@ public: case SLA_LOAD: { size_t length; switch (cmd) { - case SL_VAR: length = SlReadUint32(); break; - case SL_REF: length = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : SlReadUint32(); break; + case SL_VAR: length = SlReadListLength(); break; + case SL_REF: length = SlReadListLength(); break; default: NOT_REACHED(); } @@ -1629,10 +1656,11 @@ static inline size_t SlCalcRefListLen(const void *list) { const PtrList *l = (const PtrList *) list; - int type_size = IsSavegameVersionBefore(SLV_69) ? 2 : 4; - /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length + int type_size = SlGetListTypeLengthSize(l->size()); + int item_size = SlCalcRefLen(); + /* Each entry is saved as item_size bytes, plus type_size bytes are used for the length * of the list */ - return l->size() * type_size + type_size; + return l->size() * item_size + type_size; } /** @@ -1643,9 +1671,10 @@ static inline size_t SlCalcRefListLen(const void *list) static inline size_t SlCalcVarListLen(const void *list, size_t item_size) { const PtrList *l = (const PtrList *) list; - /* Each entry is saved as item_size bytes, plus 4 bytes are used for the length + int type_size = SlGetListTypeLengthSize(l->size()); + /* Each entry is saved as item_size bytes, plus type_size bytes are used for the length * of the list */ - return l->size() * item_size + 4; + return l->size() * item_size + type_size; } /** @@ -1665,7 +1694,7 @@ static void SlRefList(void *list, SLRefType conv) switch (_sl.action) { case SLA_SAVE: { - SlWriteUint32((uint32_t)l->size()); + SlWriteListLength(l->size()); for (auto iter = l->begin(); iter != l->end(); ++iter) { void *ptr = *iter; @@ -1675,7 +1704,7 @@ static void SlRefList(void *list, SLRefType conv) } case SLA_LOAD_CHECK: case SLA_LOAD: { - size_t length = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : SlReadUint32(); + size_t length = SlReadListLength(); if constexpr (!std::is_same_v>) { l->reserve(length); } @@ -1718,7 +1747,7 @@ static void SlVarList(void *list, VarType conv) switch (_sl.action) { case SLA_SAVE: { - SlWriteUint32((uint32_t)l->size()); + SlWriteListLength(l->size()); typename PtrList::iterator iter; for (iter = l->begin(); iter != l->end(); ++iter) { @@ -1728,7 +1757,7 @@ static void SlVarList(void *list, VarType conv) } case SLA_LOAD_CHECK: case SLA_LOAD: { - size_t length = SlReadUint32(); + size_t length = SlReadListLength(); l->resize(length); typename PtrList::iterator iter; From cf573d4bf88f4bdf534a75ba2d2a121728085819 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 18:00:59 +0100 Subject: [PATCH 061/107] Saveload: Use table format for tracerestrict chunks --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/tracerestrict_sl.cpp | 97 +++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 79041c07a4..5168991b83 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -76,7 +76,7 @@ static uint32_t saveSTC(const SlxiSubChunkInfo *info, bool dry_run); const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_VERSION_LABEL, XSCF_IGNORABLE_ALL, 1, 1, "version_label", saveVL, loadVL, nullptr }, { XSLFI_UPSTREAM_VERSION, XSCF_NULL, 1, 1, "upstream_version", saveUV, loadUV, nullptr }, - { XSLFI_TRACE_RESTRICT, XSCF_NULL, 17, 17, "tracerestrict", nullptr, nullptr, "TRRM,TRRP,TRRS" }, + { XSLFI_TRACE_RESTRICT, XSCF_NULL, 18, 18, "tracerestrict", nullptr, nullptr, "TRRM,TRRP,TRRS" }, { XSLFI_TRACE_RESTRICT_OWNER, XSCF_NULL, 1, 1, "tracerestrict_owner", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_ORDRCND, XSCF_NULL, 4, 4, "tracerestrict_order_cond", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_STATUSCND, XSCF_NULL, 2, 2, "tracerestrict_status_cond", nullptr, nullptr, nullptr }, diff --git a/src/sl/tracerestrict_sl.cpp b/src/sl/tracerestrict_sl.cpp index d49b42fbd8..756c2540b7 100644 --- a/src/sl/tracerestrict_sl.cpp +++ b/src/sl/tracerestrict_sl.cpp @@ -14,8 +14,8 @@ #include "saveload.h" #include -static const SaveLoad _trace_restrict_mapping_desc[] = { - SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32), +static const NamedSaveLoad _trace_restrict_mapping_desc[] = { + NSL("program_id", SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32)), }; /** @@ -23,10 +23,12 @@ static const SaveLoad _trace_restrict_mapping_desc[] = { */ static void Load_TRRM() { + std::vector slt = SlTableHeaderOrRiff(_trace_restrict_mapping_desc); + int index; while ((index = SlIterateArray()) != -1) { TraceRestrictMappingItem &item = _tracerestrictprogram_mapping[index]; - SlObject(&item, _trace_restrict_mapping_desc); + SlObjectLoadFiltered(&item, slt); } } @@ -35,24 +37,31 @@ static void Load_TRRM() */ static void Save_TRRM() { + std::vector slt = SlTableHeader(_trace_restrict_mapping_desc); + for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin(); iter != _tracerestrictprogram_mapping.end(); ++iter) { SlSetArrayIndex(iter->first); - SlObject(&(iter->second), _trace_restrict_mapping_desc); + SlObjectSaveFiltered(&(iter->second), slt); } } +static const NamedSaveLoad _trace_restrict_program_desc[] = { + NSL("items", SLE_VARVEC(TraceRestrictProgram, items, SLE_UINT32)), +}; + /** * Load program pool */ static void Load_TRRP() { + std::vector slt = SlTableHeaderOrRiff(_trace_restrict_program_desc); + int index; while ((index = SlIterateArray()) != -1) { TraceRestrictProgram *prog = new (index) TraceRestrictProgram(); - uint32_t prog_length = SlReadUint32(); - prog->items.resize(prog_length); - if (prog_length > 0) SlArray(prog->items.data(), prog_length, SLE_UINT32); + SlObjectLoadFiltered(prog, slt); + if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) { for (size_t i = 0; i < prog->items.size(); i++) { TraceRestrictItem &item = prog->items[i]; // note this is a reference, @@ -102,28 +111,20 @@ static void Load_TRRP() */ static void Save_TRRP() { + std::vector slt = SlTableHeader(_trace_restrict_program_desc); + for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) { SlSetArrayIndex(prog->index); - SlSetLength(4 + (prog->items.size() * 4)); - SlWriteUint32((uint32_t)prog->items.size()); - SlArray(prog->items.data(), prog->items.size(), SLE_UINT32); + SlObjectSaveFiltered(prog, slt); } } -/** program length save header struct */ -struct TraceRestrictSlotStub { - uint32_t length; -}; - -static const SaveLoad _trace_restrict_slot_stub_desc[] = { - SLE_VAR(TraceRestrictSlotStub, length, SLE_UINT32), -}; - -static const SaveLoad _trace_restrict_slot_desc[] = { - SLE_VAR(TraceRestrictSlot, max_occupancy, SLE_UINT32), - SLE_SSTR(TraceRestrictSlot, name, SLF_ALLOW_CONTROL), - SLE_VAR(TraceRestrictSlot, owner, SLE_UINT8), - SLE_CONDVAR_X(TraceRestrictSlot, vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRACE_RESTRICT, 13)), +static const NamedSaveLoad _trace_restrict_slot_desc[] = { + NSL("max_occupancy", SLE_VAR(TraceRestrictSlot, max_occupancy, SLE_UINT32)), + NSL("name", SLE_SSTR(TraceRestrictSlot, name, SLE_STR | SLF_ALLOW_CONTROL)), + NSL("owner", SLE_VAR(TraceRestrictSlot, owner, SLE_UINT8)), + NSL("vehicle_type", SLE_CONDVAR_X(TraceRestrictSlot, vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRACE_RESTRICT, 13))), + NSL("occupants", SLE_VARVEC(TraceRestrictSlot, occupants, SLE_UINT32)), }; /** @@ -131,45 +132,33 @@ static const SaveLoad _trace_restrict_slot_desc[] = { */ static void Load_TRRS() { + std::vector slt = SlTableHeaderOrRiff(_trace_restrict_slot_desc); + int index; - TraceRestrictSlotStub stub; while ((index = SlIterateArray()) != -1) { TraceRestrictSlot *slot = new (index) TraceRestrictSlot(); - SlObject(slot, _trace_restrict_slot_desc); - SlObject(&stub, _trace_restrict_slot_stub_desc); - slot->occupants.resize(stub.length); - if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); + SlObjectLoadFiltered(slot, slt); } TraceRestrictSlot::RebuildVehicleIndex(); } -/** - * Save a slot, used by SlAutolength - */ -static void RealSave_TRRS(TraceRestrictSlot *slot) -{ - SlObject(slot, _trace_restrict_slot_desc); - TraceRestrictSlotStub stub; - stub.length = (uint32_t)slot->occupants.size(); - SlObject(&stub, _trace_restrict_slot_stub_desc); - if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); -} - /** * Save slot pool */ static void Save_TRRS() { + std::vector slt = SlTableHeader(_trace_restrict_slot_desc); + for (TraceRestrictSlot *slot : TraceRestrictSlot::Iterate()) { SlSetArrayIndex(slot->index); - SlAutolength((AutolengthProc*) RealSave_TRRS, slot); + SlObjectSaveFiltered(slot, slt); } } -static const SaveLoad _trace_restrict_counter_desc[] = { - SLE_VAR(TraceRestrictCounter, value, SLE_INT32), - SLE_SSTR(TraceRestrictCounter, name, SLF_ALLOW_CONTROL), - SLE_VAR(TraceRestrictCounter, owner, SLE_UINT8), +static const NamedSaveLoad _trace_restrict_counter_desc[] = { + NSL("value", SLE_VAR(TraceRestrictCounter, value, SLE_INT32)), + NSL("name", SLE_SSTR(TraceRestrictCounter, name, SLE_STR | SLF_ALLOW_CONTROL)), + NSL("owner", SLE_VAR(TraceRestrictCounter, owner, SLE_UINT8)), }; /** @@ -177,10 +166,12 @@ static const SaveLoad _trace_restrict_counter_desc[] = { */ static void Load_TRRC() { + std::vector slt = SlTableHeaderOrRiff(_trace_restrict_counter_desc); + int index; while ((index = SlIterateArray()) != -1) { TraceRestrictCounter *ctr = new (index) TraceRestrictCounter(); - SlObject(ctr, _trace_restrict_counter_desc); + SlObjectLoadFiltered(ctr, slt); } } @@ -189,9 +180,11 @@ static void Load_TRRC() */ static void Save_TRRC() { + std::vector slt = SlTableHeader(_trace_restrict_counter_desc); + for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { SlSetArrayIndex(ctr->index); - SlObject(ctr, _trace_restrict_counter_desc); + SlObjectSaveFiltered(ctr, slt); } } @@ -207,10 +200,10 @@ void AfterLoadTraceRestrict() } extern const ChunkHandler trace_restrict_chunk_handlers[] = { - { 'TRRM', Save_TRRM, Load_TRRM, nullptr, nullptr, CH_SPARSE_ARRAY }, // Trace Restrict Mapping chunk - { 'TRRP', Save_TRRP, Load_TRRP, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Mapping Program Pool chunk - { 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Slot Pool chunk - { 'TRRC', Save_TRRC, Load_TRRC, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Counter Pool chunk + { 'TRRM', Save_TRRM, Load_TRRM, nullptr, nullptr, CH_SPARSE_TABLE }, // Trace Restrict Mapping chunk + { 'TRRP', Save_TRRP, Load_TRRP, nullptr, nullptr, CH_TABLE }, // Trace Restrict Mapping Program Pool chunk + { 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_TABLE }, // Trace Restrict Slot Pool chunk + { 'TRRC', Save_TRRC, Load_TRRC, nullptr, nullptr, CH_TABLE }, // Trace Restrict Counter Pool chunk }; extern const ChunkHandlerTable _trace_restrict_chunk_handlers(trace_restrict_chunk_handlers); From 8d9c988767b2b0e8c058030a377c23d036a6c586 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 18:20:30 +0100 Subject: [PATCH 062/107] Saveload: Rename CH_UNUSED to CH_READONLY --- src/sl/debug_sl.cpp | 4 ++-- src/sl/misc_sl.cpp | 2 +- src/sl/saveload.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sl/debug_sl.cpp b/src/sl/debug_sl.cpp index 0a8df9d242..7eb603eb5e 100644 --- a/src/sl/debug_sl.cpp +++ b/src/sl/debug_sl.cpp @@ -108,8 +108,8 @@ static void Check_DBGD() } extern const ChunkHandler debug_chunk_handlers[] = { - { 'DBGL', nullptr, Load_DBGL, nullptr, Check_DBGL, CH_UNUSED }, - { 'DBGC', nullptr, Load_DBGC, nullptr, Check_DBGC, CH_UNUSED }, + { 'DBGL', nullptr, Load_DBGL, nullptr, Check_DBGL, CH_READONLY }, + { 'DBGC', nullptr, Load_DBGC, nullptr, Check_DBGC, CH_READONLY }, { 'DBGD', Save_DBGD, Load_DBGD, nullptr, Check_DBGD, CH_TABLE }, }; diff --git a/src/sl/misc_sl.cpp b/src/sl/misc_sl.cpp index 44cd01f2f6..a3c1534f1a 100644 --- a/src/sl/misc_sl.cpp +++ b/src/sl/misc_sl.cpp @@ -210,7 +210,7 @@ static void Load_MISC() static const ChunkHandler misc_chunk_handlers[] = { { 'DATE', Save_DATE, Load_DATE, nullptr, Check_DATE, CH_TABLE }, MakeSaveUpstreamFeatureConditionalLoadUpstreamChunkHandler<'VIEW', XSLFI_TABLE_MISC_SL>(Load_VIEW, nullptr, nullptr), - { 'MISC', nullptr, Load_MISC, nullptr, nullptr, CH_UNUSED }, + { 'MISC', nullptr, Load_MISC, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _misc_chunk_handlers(misc_chunk_handlers); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 31e8a02d97..291630e9fb 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -112,7 +112,7 @@ enum ChunkType { CH_SPARSE_TABLE = 4, CH_EXT_HDR = 15, ///< Extended chunk header - CH_UNUSED = 0x80, + CH_READONLY = 0x80, }; /** Handlers and description of chunk. */ @@ -180,7 +180,7 @@ namespace upstream_sl { SlUnreachablePlaceholder, SlUnreachablePlaceholder, SlUnreachablePlaceholder, - CH_UNUSED + CH_READONLY }; ch.special_proc = [](uint32_t chunk_id, ChunkSaveLoadSpecialOp op) -> ChunkSaveLoadSpecialOpResult { assert(id == chunk_id); @@ -262,7 +262,7 @@ namespace upstream_sl { template ChunkHandler MakeSaveUpstreamFeatureConditionalLoadUpstreamChunkHandler(ChunkSaveLoadProc *load_proc, ChunkSaveLoadProc *ptrs_proc, ChunkSaveLoadProc *load_check_proc) { - return MakeConditionallyUpstreamChunkHandler>(nullptr, load_proc, ptrs_proc, load_check_proc, CH_UNUSED); + return MakeConditionallyUpstreamChunkHandler>(nullptr, load_proc, ptrs_proc, load_check_proc, CH_READONLY); } } From 3202fc2ce35acc10bef13299952aa1a9c567e2f7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 18:23:22 +0100 Subject: [PATCH 063/107] Saveload: Change type of read-only chunks to CH_READONLY --- src/sl/economy_sl.cpp | 4 ++-- src/sl/plans_sl.cpp | 2 +- src/sl/station_sl.cpp | 2 +- src/sl/strings_sl.cpp | 2 +- src/sl/waypoint_sl.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sl/economy_sl.cpp b/src/sl/economy_sl.cpp index e5fd195b21..7509b4cce9 100644 --- a/src/sl/economy_sl.cpp +++ b/src/sl/economy_sl.cpp @@ -83,8 +83,8 @@ static void Ptrs_CAPY() static const ChunkHandler economy_chunk_handlers[] = { MakeSaveUpstreamFeatureConditionalLoadUpstreamChunkHandler<'CAPY', XSLFI_TABLE_MISC_SL, 2>(Load_CAPY, Ptrs_CAPY, nullptr), - { 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_RIFF }, - { 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_RIFF }, + { 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_READONLY }, + { 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_READONLY }, MakeSaveUpstreamFeatureConditionalLoadUpstreamChunkHandler<'ECMY', XSLFI_TABLE_MISC_SL, 2>(Load_ECMY, nullptr, nullptr), }; diff --git a/src/sl/plans_sl.cpp b/src/sl/plans_sl.cpp index d1ad20c0c0..89e83dd07e 100644 --- a/src/sl/plans_sl.cpp +++ b/src/sl/plans_sl.cpp @@ -91,7 +91,7 @@ static void Load_PLANLINE() /** Chunk handlers related to plans. */ static const ChunkHandler plan_chunk_handlers[] = { { 'PLAN', Save_PLAN, Load_PLAN, nullptr, nullptr, CH_ARRAY }, - { 'PLLN', nullptr, Load_PLANLINE, nullptr, nullptr, CH_ARRAY }, + { 'PLLN', nullptr, Load_PLANLINE, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _plan_chunk_handlers(plan_chunk_handlers); diff --git a/src/sl/station_sl.cpp b/src/sl/station_sl.cpp index 523228a21c..7acb434382 100644 --- a/src/sl/station_sl.cpp +++ b/src/sl/station_sl.cpp @@ -862,7 +862,7 @@ static const ChunkHandler station_chunk_handlers[] = { { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_ARRAY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY }, { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY }, - { 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_ARRAY }, + { 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _station_chunk_handlers(station_chunk_handlers); diff --git a/src/sl/strings_sl.cpp b/src/sl/strings_sl.cpp index 6ac548a178..87717f2ce8 100644 --- a/src/sl/strings_sl.cpp +++ b/src/sl/strings_sl.cpp @@ -132,7 +132,7 @@ static void Load_NAME() /** Chunk handlers related to strings. */ static const ChunkHandler name_chunk_handlers[] = { - { 'NAME', nullptr, Load_NAME, nullptr, nullptr, CH_ARRAY }, + { 'NAME', nullptr, Load_NAME, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _name_chunk_handlers(name_chunk_handlers); diff --git a/src/sl/waypoint_sl.cpp b/src/sl/waypoint_sl.cpp index 2a2192cce9..275b52b22d 100644 --- a/src/sl/waypoint_sl.cpp +++ b/src/sl/waypoint_sl.cpp @@ -223,7 +223,7 @@ static void Ptrs_WAYP() } static const ChunkHandler waypoint_chunk_handlers[] = { - { 'CHKP', nullptr, Load_WAYP, Ptrs_WAYP, nullptr, CH_ARRAY }, + { 'CHKP', nullptr, Load_WAYP, Ptrs_WAYP, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _waypoint_chunk_handlers(waypoint_chunk_handlers); From 3035b91b5cc2cf31f1b765392a07907a1f6d2516 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 18:48:25 +0100 Subject: [PATCH 064/107] Saveload: Use table format for speed adaptation chunk --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/train_speed_adaptation.cpp | 42 +++++++++++++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 5168991b83..0eba2cc3fb 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -163,7 +163,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr }, { XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr }, { XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 2, 2, "station_cargo_history", nullptr, nullptr, nullptr }, - { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 2, 2, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, + { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 3, 3, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, { XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, diff --git a/src/sl/train_speed_adaptation.cpp b/src/sl/train_speed_adaptation.cpp index 55ab6692b8..93817351ed 100644 --- a/src/sl/train_speed_adaptation.cpp +++ b/src/sl/train_speed_adaptation.cpp @@ -13,47 +13,45 @@ using SignalSpeedType = std::pair; -static const SaveLoad _train_speed_adaptation_map_desc[] = { - SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 1, 1)), - SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 2)), - SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8), - SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16), - SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64), +static const NamedSaveLoad _train_speed_adaptation_map_desc[] = { + NSLT("signal_tile", SLE_VAR(SignalSpeedType, first.signal_tile, SLE_UINT32)), + NSL("signal_track", SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 1, 1))), + NSL("signal_track", SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 2))), + NSL("last_passing_train_dir", SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8)), + NSL("train_speed", SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16)), + NSL("time_stamp", SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64)), }; -static std::vector _filtered_train_speed_adaptation_map_desc; - static void Load_TSAS() { - _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc); + const bool table_mode = SlIsTableChunk(); + std::vector slt = SlTableHeaderOrRiff(_train_speed_adaptation_map_desc); + int index; SignalSpeedType data; while ((index = SlIterateArray()) != -1) { - const_cast(data.first).signal_tile = index; - SlObjectLoadFiltered(&data, _filtered_train_speed_adaptation_map_desc); + if (!table_mode) { + const_cast(data.first).signal_tile = index; + } + SlObjectLoadFiltered(&data, slt); _signal_speeds.insert(data); } - _filtered_train_speed_adaptation_map_desc.clear(); -} - -static void RealSave_TSAS(SignalSpeedType *data) -{ - SlObjectSaveFiltered(data, _filtered_train_speed_adaptation_map_desc); } static void Save_TSAS() { - _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc); + std::vector slt = SlTableHeader(_train_speed_adaptation_map_desc); + + int index = 0; for (auto &it : _signal_speeds) { - SlSetArrayIndex(it.first.signal_tile); + SlSetArrayIndex(index++); SignalSpeedType *data = ⁢ - SlAutolength((AutolengthProc*) RealSave_TSAS, data); + SlObjectSaveFiltered(data, slt); } - _filtered_train_speed_adaptation_map_desc.clear(); } extern const ChunkHandler train_speed_adaptation_chunk_handlers[] = { - { 'TSAS', Save_TSAS, Load_TSAS, nullptr, nullptr, CH_SPARSE_ARRAY }, + { 'TSAS', Save_TSAS, Load_TSAS, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _train_speed_adaptation_chunk_handlers(train_speed_adaptation_chunk_handlers); From 2bf05321bb4ff53b3b857ccc42a430703eb8b1c8 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 18:48:37 +0100 Subject: [PATCH 065/107] Saveload: Use table format for tunnel chunk --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/tunnel_sl.cpp | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 0eba2cc3fb..c7ba34afca 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -116,7 +116,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 2, 2, "extended_gamelog", nullptr, nullptr, nullptr }, { XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", nullptr, nullptr, nullptr }, { XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 4, 4, "custom_bridge_heads", nullptr, nullptr, nullptr }, - { XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" }, + { XSLFI_CHUNNEL, XSCF_NULL, 3, 3, "chunnel", nullptr, nullptr, "TUNN" }, { XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 8, 8, "scheduled_dispatch", nullptr, nullptr, nullptr }, { XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr }, { XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr }, diff --git a/src/sl/tunnel_sl.cpp b/src/sl/tunnel_sl.cpp index 769152ca08..43461b8e55 100644 --- a/src/sl/tunnel_sl.cpp +++ b/src/sl/tunnel_sl.cpp @@ -15,36 +15,39 @@ #include "../safeguards.h" -static const SaveLoad _tunnel_desc[] = { - SLE_CONDVAR(Tunnel, tile_n, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION), - SLE_CONDVAR(Tunnel, tile_s, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION), - SLE_CONDVAR(Tunnel, height, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION), - SLE_CONDVAR(Tunnel, is_chunnel, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION), - SLE_CONDVAR_X(Tunnel, style, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEW_SIGNAL_STYLES)), +static const NamedSaveLoad _tunnel_desc[] = { + NSL("tile_n", SLE_VAR(Tunnel, tile_n, SLE_UINT32)), + NSL("tile_s", SLE_VAR(Tunnel, tile_s, SLE_UINT32)), + NSL("height", SLE_VAR(Tunnel, height, SLE_UINT8)), + NSL("is_chunnel", SLE_VAR(Tunnel, is_chunnel, SLE_BOOL)), + NSL("style", SLE_CONDVAR_X(Tunnel, style, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_NEW_SIGNAL_STYLES))), }; static void Save_TUNN() { + std::vector slt = SlTableHeader(_tunnel_desc); + for (Tunnel *tunnel : Tunnel::Iterate()) { SlSetArrayIndex(tunnel->index); - SlObject(tunnel, _tunnel_desc); + SlObjectSaveFiltered(tunnel, slt); } } static void Load_TUNN() { - int index; + std::vector slt = SlTableHeaderOrRiff(_tunnel_desc); + int index; while ((index = SlIterateArray()) != -1) { Tunnel *tunnel = new (index) Tunnel(); - SlObject(tunnel, _tunnel_desc); + SlObjectLoadFiltered(tunnel, slt); tunnel->UpdateIndexes(); } } extern const ChunkHandler tunnel_chunk_handlers[] = { - { 'TUNN', Save_TUNN, Load_TUNN, nullptr, nullptr, CH_ARRAY }, + { 'TUNN', Save_TUNN, Load_TUNN, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _tunnel_chunk_handlers(tunnel_chunk_handlers); From c2a4ddea7e987d4b91195c90b6202b01e190e943 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 19:10:59 +0100 Subject: [PATCH 066/107] Saveload: Use table format for XBSS chunk --- src/sl/bridge_signal_sl.cpp | 34 +++++++++++----------------------- src/sl/extended_ver_sl.cpp | 2 +- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/sl/bridge_signal_sl.cpp b/src/sl/bridge_signal_sl.cpp index 7ae34e8095..0a06688fb7 100644 --- a/src/sl/bridge_signal_sl.cpp +++ b/src/sl/bridge_signal_sl.cpp @@ -12,41 +12,29 @@ #include "saveload.h" #include -/** stub save header struct */ -struct LongBridgeSignalStorageStub { - uint32_t length; -}; - -static const SaveLoad _long_bridge_signal_storage_stub_desc[] = { - SLE_VAR(LongBridgeSignalStorageStub, length, SLE_UINT32), +static const NamedSaveLoad _long_bridge_signal_storage_desc[] = { + NSL("signal_red_bits", SLE_VARVEC(LongBridgeSignalStorage, signal_red_bits, SLE_UINT64)), }; static void Load_XBSS() { + std::vector slt = SlTableHeaderOrRiff(_long_bridge_signal_storage_desc); + int index; - LongBridgeSignalStorageStub stub; while ((index = SlIterateArray()) != -1) { LongBridgeSignalStorage &lbss = _long_bridge_signal_sim_map[index]; - SlObject(&stub, _long_bridge_signal_storage_stub_desc); - lbss.signal_red_bits.resize(stub.length); - SlArray(lbss.signal_red_bits.data(), stub.length, SLE_UINT64); + SlObjectLoadFiltered(&lbss, slt); } } -static void RealSave_XBSS(const LongBridgeSignalStorage *lbss) -{ - LongBridgeSignalStorageStub stub; - stub.length = (uint32_t)lbss->signal_red_bits.size(); - SlObject(&stub, _long_bridge_signal_storage_stub_desc); - SlArray(const_cast(lbss->signal_red_bits.data()), stub.length, SLE_UINT64); -} - static void Save_XBSS() { - for (const auto &it : _long_bridge_signal_sim_map) { - const LongBridgeSignalStorage &lbss = it.second; + std::vector slt = SlTableHeader(_long_bridge_signal_storage_desc); + + for (auto &it : _long_bridge_signal_sim_map) { + LongBridgeSignalStorage &lbss = it.second; SlSetArrayIndex(it.first); - SlAutolength((AutolengthProc*) RealSave_XBSS, const_cast(&lbss)); + SlObjectSaveFiltered(&lbss, slt); } } @@ -67,7 +55,7 @@ static void Save_XBST() } extern const ChunkHandler bridge_signal_chunk_handlers[] = { - { 'XBSS', Save_XBSS, Load_XBSS, nullptr, nullptr, CH_SPARSE_ARRAY }, + { 'XBSS', Save_XBSS, Load_XBSS, nullptr, nullptr, CH_SPARSE_TABLE }, { 'XBST', Save_XBST, Load_XBST, nullptr, nullptr, CH_RIFF }, }; diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index c7ba34afca..6ea0e0c52e 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -95,7 +95,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", nullptr, nullptr, nullptr }, { XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 3, 3, "timetable_start_ticks", nullptr, nullptr, nullptr }, { XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 3, 3, "town_cargo_adj", nullptr, nullptr, nullptr }, - { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 10, 10, "signal_tunnel_bridge", nullptr, nullptr, "XBSS" }, + { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 11, 11, "signal_tunnel_bridge", nullptr, nullptr, "XBSS" }, { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 8, 8, "improved_breakdowns", nullptr, nullptr, nullptr }, { XSLFI_CONSIST_BREAKDOWN_FLAG, XSCF_NULL, 1, 1, "consist_breakdown_flag", nullptr, nullptr, nullptr }, { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 2, 2, "tt_wait_in_depot", nullptr, nullptr, nullptr }, From 94e5555419f2f596bf588f6523fc3f10daaa6e6a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 19:22:04 +0100 Subject: [PATCH 067/107] Extend description text for station cargo distribution setting --- src/lang/extra/english.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index cab5541111..f4e9f2945c 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -184,7 +184,7 @@ STR_CONFIG_SETTING_STATION_RATING_SIZE_CARGO_AMOUNT :Station cargo c STR_CONFIG_SETTING_STATION_RATING_SIZE_CARGO_AMOUNT_HELPTEXT :When enabled, the cargo capacity of stations before waiting cargo is truncated and the effect of the waiting cargo amount on the station rating for that cargo depend on the size of the station. Larger stations can store more cargo and are more tolerant of large amounts of waiting cargo. STR_CONFIG_SETTING_CARGO_DELIVERY_MODE :Cargo delivery distribution mode: {STRING2} -STR_CONFIG_SETTING_CARGO_DELIVERY_MODE_HELPTEXT :The method used to deliver cargo to industries surrounding a station. +STR_CONFIG_SETTING_CARGO_DELIVERY_MODE_HELPTEXT :The method used to distribute cargo delivered to a station to industries in the station's catchment area.{}The "original" mode distributes all cargo to the closest industry (measured from the station sign tile).{}The "balanced" mode distributes cargo equally to all accepting industries in the station's catchment area. STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL :Train braking model: {STRING2} STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL_HELPTEXT :Select the physics model for train braking. The "original" model allows trains to stop instantly. In the "realistic" model, trains have a stopping distance and will reserve ahead accordingly, trains cannot stop instantly.{}{}The "realistic" model has many implications for signalling and track layout design, and is therefore an advanced feature which may not be suitable for beginners. In particular pre-signals and two-way signals are not permitted, and PBS is used for all signalling. From a07b02ebe4685f7f379e789309189a538605b79d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 8 Jul 2024 19:37:27 +0100 Subject: [PATCH 068/107] Saveload: Use table format for new signal style mapping chunk --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/newsignals_sl.cpp | 41 +++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 6ea0e0c52e..819b97c82f 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -180,7 +180,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_GRF_ROADSTOPS, XSCF_NULL, 3, 3, "grf_road_stops", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr }, - { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 2, 2, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, + { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 3, 3, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, { XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr }, { XSLFI_TOWN_SETTING_OVERRIDE, XSCF_NULL, 1, 1, "town_setting_override", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_SPARSE_EDGES, XSCF_NULL, 1, 1, "linkgraph_sparse_edges", nullptr, nullptr, nullptr }, diff --git a/src/sl/newsignals_sl.cpp b/src/sl/newsignals_sl.cpp index 6ae3626fae..bfaef5bc2b 100644 --- a/src/sl/newsignals_sl.cpp +++ b/src/sl/newsignals_sl.cpp @@ -14,13 +14,19 @@ #include "../safeguards.h" +static const NamedSaveLoad _new_signal_style_mapping_desc[] = { + NSLT("grfid", SLE_VAR(NewSignalStyleMapping, grfid, SLE_UINT32)), + NSLT("grf_local_id", SLE_VAR(NewSignalStyleMapping, grf_local_id, SLE_UINT8)), +}; + static void Save_NSID() { - SlSetLength(4 + (_new_signal_style_mapping.size() * 5)); - SlWriteUint32((uint)_new_signal_style_mapping.size()); - for (const NewSignalStyleMapping &mapping : _new_signal_style_mapping) { - SlWriteUint32(mapping.grfid); - SlWriteByte(mapping.grf_local_id); + std::vector slt = SlTableHeader(_new_signal_style_mapping_desc); + + int index = 0; + for (NewSignalStyleMapping &it : _new_signal_style_mapping) { + SlSetArrayIndex(index++); + SlObjectSaveFiltered(&it, slt); } } @@ -28,17 +34,28 @@ static void Load_NSID() { _new_signal_style_mapping.fill({}); - uint count = SlReadUint32(); - for (uint i = 0; i < count; i++) { - NewSignalStyleMapping mapping; - mapping.grfid = SlReadUint32(); - mapping.grf_local_id = SlReadByte(); - if (i < _new_signal_style_mapping.size()) _new_signal_style_mapping[i] = mapping; + if (SlIsTableChunk()) { + std::vector slt = SlTableHeader(_new_signal_style_mapping_desc); + + int index; + while ((index = SlIterateArray()) != -1) { + NewSignalStyleMapping mapping; + SlObjectLoadFiltered(&mapping, slt); + if (static_cast(index) < _new_signal_style_mapping.size()) _new_signal_style_mapping[index] = mapping; + } + } else { + uint count = SlReadUint32(); + for (uint i = 0; i < count; i++) { + NewSignalStyleMapping mapping; + mapping.grfid = SlReadUint32(); + mapping.grf_local_id = SlReadByte(); + if (i < _new_signal_style_mapping.size()) _new_signal_style_mapping[i] = mapping; + } } } static const ChunkHandler new_signal_chunk_handlers[] = { - { 'NSID', Save_NSID, Load_NSID, nullptr, nullptr, CH_RIFF }, + { 'NSID', Save_NSID, Load_NSID, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _new_signal_chunk_handlers(new_signal_chunk_handlers); From 7152f534e85ecf73786f8d38d106dd06d91cd4d6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 10 Jul 2024 21:53:00 +0100 Subject: [PATCH 069/107] Tunnel/bridge: Fix comments for some map accessor functions --- src/tunnelbridge_map.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tunnelbridge_map.h b/src/tunnelbridge_map.h index 49f956cb58..571bea4450 100644 --- a/src/tunnelbridge_map.h +++ b/src/tunnelbridge_map.h @@ -369,7 +369,7 @@ inline bool IsTunnelBridgeWithSignalSimulation(TileIndex t) /** * Is this a tunnel/bridge entrance tile with signal? * Tunnel bridge signal simulation has allways bit 5 on at entrance. - * @param t the tile that might be a tunnel/bridge. + * @param t the tunnel/bridge tile. * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if this tile is a tunnel/bridge entrance. */ @@ -392,7 +392,7 @@ inline bool IsTunnelBridgeSignalSimulationEntranceTile(TileIndex t) /** * Is this a tunnel/bridge entrance tile with signal only? - * @param t the tile that might be a tunnel/bridge. + * @param t the tunnel/bridge tile. * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if this tile is a tunnel/bridge entrance only. */ @@ -404,7 +404,7 @@ inline bool IsTunnelBridgeSignalSimulationEntranceOnly(TileIndex t) /** * Is this a tunnel/bridge exit? - * @param t the tile that might be a tunnel/bridge. + * @param t the tunnel/bridge tile. * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if this tile is a tunnel/bridge exit. */ @@ -426,7 +426,7 @@ inline bool IsTunnelBridgeSignalSimulationExitTile(TileIndex t) /** * Is this a tunnel/bridge exit only? - * @param t the tile that might be a tunnel/bridge. + * @param t the tunnel/bridge tile. * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if this tile is a tunnel/bridge exit only. */ From 9ae96d2fdbb7ada06a874070dc6c68c61509b352 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 10 Jul 2024 21:46:05 +0100 Subject: [PATCH 070/107] Fix YAPF not considering signalled tunnel/bridges as safe waiting tiles In search for any safe waiting tile mode --- src/pathfinder/yapf/yapf_costrail.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index d9ed73c2d5..119d9a762d 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -473,7 +473,7 @@ public: return -1; } } - if (n.flags_u.flags_s.m_reverse_pending && entering && IsTunnelBridgeSignalSimulationEntrance(tile)) { + if ((TrackFollower::DoTrackMasking() || n.flags_u.flags_s.m_reverse_pending) && entering && IsTunnelBridgeSignalSimulationEntrance(tile)) { n.m_segment->m_end_segment_reason |= ESRB_SAFE_TILE; } } @@ -774,6 +774,15 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END; extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; } + } else if (TrackFollower::DoTrackMasking() && + _settings_game.pf.back_of_one_way_pbs_waiting_point && + IsTunnelBridgeWithSignalSimulation(next.tile) && + IsTunnelBridgeSignalSimulationExitOnly(next.tile) && + IsTunnelBridgePBS(next.tile) && + TrackdirEntersTunnelBridge(next.tile, next.td)) { + /* Possible safe tile, but not so good as it's the back of a signal... */ + end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END; + extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; } /* Check the next tile for the rail type. */ From 93ecef7de20f35d552a368c5ab40e15a246a0f8a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 10 Jul 2024 22:15:59 +0100 Subject: [PATCH 071/107] Fix parameter forwarding in Rail90DegTurnDisallowed helpers --- src/rail.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rail.h b/src/rail.h index 57d7a75a37..8546169e25 100644 --- a/src/rail.h +++ b/src/rail.h @@ -398,12 +398,12 @@ inline bool Rail90DegTurnDisallowedTilesFromDiagDir(TileIndex t1, TileIndex t2, inline bool Rail90DegTurnDisallowedAdjacentTiles(TileIndex t1, TileIndex t2, bool def = _settings_game.pf.forbid_90_deg) { - return Rail90DegTurnDisallowedTilesFromDiagDir(t1, t2, DiagdirBetweenTiles(t1, t2)); + return Rail90DegTurnDisallowedTilesFromDiagDir(t1, t2, DiagdirBetweenTiles(t1, t2), def); } inline bool Rail90DegTurnDisallowedTilesFromTrackdir(TileIndex t1, TileIndex t2, Trackdir t1_td, bool def = _settings_game.pf.forbid_90_deg) { - return Rail90DegTurnDisallowedTilesFromDiagDir(t1, t2, TrackdirToExitdir(t1_td)); + return Rail90DegTurnDisallowedTilesFromDiagDir(t1, t2, TrackdirToExitdir(t1_td), def); } /** From a71f8b67036e26b76586ba1c15c722bb5fdfbf32 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 11 Jul 2024 01:13:45 +0100 Subject: [PATCH 072/107] Github: Temporarily disable vcpkg caching for linux generic builds To avoid problems where dependencies downloaded via apt change, causing the cache contents to be incorrect --- .github/workflows/release-linux.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 337e22eb50..575943def6 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -35,13 +35,13 @@ jobs: - name: Enable Rust cache uses: Swatinem/rust-cache@v2 - - name: Setup vcpkg caching - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - core.exportVariable('VCPKG_BINARY_SOURCES', 'clear;x-gha,readwrite') +# - name: Setup vcpkg caching +# uses: actions/github-script@v7 +# with: +# script: | +# core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); +# core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); +# core.exportVariable('VCPKG_BINARY_SOURCES', 'clear;x-gha,readwrite') - name: Install dependencies run: | From 2de0dd17c2d55d5eb617550f94e2fb222dc5e20d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 11 Jul 2024 01:15:20 +0100 Subject: [PATCH 073/107] Version: Committing version data for tag: jgrpp-0.60.2 --- .ottdrev-vc | 4 ++-- README.md | 2 +- jgrpp-changelog.md | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.ottdrev-vc b/.ottdrev-vc index 28531ff991..a9b41e6e48 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.60.1 20240703 0 ae516b4a869540072f86a8e041f2e2c554dd6670 1 0 2024 -30d60a49e07e9aa22f4c182f47fdf4d70392c7bafbbaf34c24461486d0d993f2 - +jgrpp-0.60.2 20240711 0 a71f8b67036e26b76586ba1c15c722bb5fdfbf32 1 0 2024 +deb34987433654358259ff990c1ce8622ba3204615c3082be2a0c6d528ebc9e4 - diff --git a/README.md b/README.md index 55827fb645..8470480720 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.60.1 +## JGR's Patchpack version 0.60.2 This is a collection of features and other modifications applied to [OpenTTD](http://www.openttd.org/). It's a separate version of the game which can be installed and played alongside the standard game, not a loadable mod (NewGRF, script, or so on). diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index c86824335f..fb35bb5aa4 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,14 @@ * * * +### v0.60.2 (2024-07-11) +* Fix crash opening landscape window when there are no available objects. +* Fix crash which can occur when NewGRFs overwrite a recolour sprite with a normal sprite. +* Fix one-way signalled bridges with parrallel diagonal tracks on the exit tile applying one-way behaviour to the bypassing track. +* Fix the acceleration/braking scaling setting not immediately updating running trains when the setting is changed, this could cause multiplayer desyncs. +* Fix the pathfinder not considering a signalled tunnel/bridge entrance or exit tile as a valid place to end a reservation in some cases. +* Bump trunk base from commit b2218e75d4dea4261c6638579d3e501080b85bdc to commit 45886e50b21fd1dee461e910267781e264574790. + ### v0.60.1 (2024-07-03) * Fix network clients being disconnected when attempting to join a multiplayer game. * Fix false-positive warning messages about inconsistencies which could cause multiplayer desyncs. From 651610cd2adaae00cf5ea48ffc662a04336ccf20 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 11 Jul 2024 01:43:18 +0100 Subject: [PATCH 074/107] Saveload: Fix sign and narrowing conversion warnings calculating list sizes --- src/sl/saveload.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 5105013099..43a1fdc1cf 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -1578,8 +1578,8 @@ public: const SlStorageT *list = static_cast(storage); - int type_size = SlGetListTypeLengthSize(list->size()); // Size of the length of the list. - int item_size = SlCalcConvFileLen(cmd == SL_VAR ? conv : (VarType)SLE_FILE_U32); + uint type_size = SlGetListTypeLengthSize(list->size()); // Size of the length of the list. + uint item_size = SlCalcConvFileLen(cmd == SL_VAR ? conv : (VarType)SLE_FILE_U32); return list->size() * item_size + type_size; } @@ -1656,8 +1656,8 @@ static inline size_t SlCalcRefListLen(const void *list) { const PtrList *l = (const PtrList *) list; - int type_size = SlGetListTypeLengthSize(l->size()); - int item_size = SlCalcRefLen(); + uint type_size = SlGetListTypeLengthSize(l->size()); + size_t item_size = SlCalcRefLen(); /* Each entry is saved as item_size bytes, plus type_size bytes are used for the length * of the list */ return l->size() * item_size + type_size; @@ -1671,7 +1671,7 @@ static inline size_t SlCalcRefListLen(const void *list) static inline size_t SlCalcVarListLen(const void *list, size_t item_size) { const PtrList *l = (const PtrList *) list; - int type_size = SlGetListTypeLengthSize(l->size()); + uint type_size = SlGetListTypeLengthSize(l->size()); /* Each entry is saved as item_size bytes, plus type_size bytes are used for the length * of the list */ return l->size() * item_size + type_size; From 14afaf810842a926fbdeba69c6a2b0f98cd21fa7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 11 Jul 2024 23:08:13 +0100 Subject: [PATCH 075/107] Sound: Changes to enable building xaudio2 driver on MinGW --- src/sound/xaudio2_s.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sound/xaudio2_s.cpp b/src/sound/xaudio2_s.cpp index e1d852000e..d80c3691f4 100644 --- a/src/sound/xaudio2_s.cpp +++ b/src/sound/xaudio2_s.cpp @@ -27,7 +27,11 @@ #include #include +#ifdef _MSC_VER #include +#else +#include +#endif #include using Microsoft::WRL::ComPtr; @@ -121,12 +125,16 @@ static StreamingVoiceContext *_voice_context = nullptr; static HRESULT CreateXAudio(API_XAudio2Create xAudio2Create) { HRESULT hr; +#ifdef _MSC_VER __try { +#endif UINT32 flags = 0; hr = xAudio2Create(_xaudio2.GetAddressOf(), flags, XAUDIO2_DEFAULT_PROCESSOR); +#ifdef _MSC_VER } __except (EXCEPTION_EXECUTE_HANDLER) { hr = GetExceptionCode(); } +#endif return hr; } From cac020b7e6cf05826830b426fa20b5565bc93d3f Mon Sep 17 00:00:00 2001 From: Qwest8K <38340995+Qwest8K@users.noreply.github.com> Date: Fri, 12 Jul 2024 01:16:37 +0300 Subject: [PATCH 076/107] Update: Russian translation up to v0.60.2 (#715) --- src/lang/extra/russian.txt | 136 ++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/lang/extra/russian.txt b/src/lang/extra/russian.txt index 45421d276c..e403f12bc0 100644 --- a/src/lang/extra/russian.txt +++ b/src/lang/extra/russian.txt @@ -51,11 +51,11 @@ STR_UNIT_NAME_VELOCITY_GAMEUNITS :клеток/д STR_UNIT_NAME_VELOCITY_GAMEUNITS_WALLCLOCK :клеток/сек STR_UNITS_SECONDS_SHORT :{COMMA}{NBSP}с -STR_UNITS_PRODUCTION_INTERVALS :{NUM}{NBSP}производственный интервал{P "" а ов} +STR_UNITS_PRODUCTION_INTERVALS :{NUM}{NBSP}интервал{P "" а ов} производства STR_BUTTON_RENAME :{BLACK}Переименовать -STR_MEASURE_DIST_HEIGHTDIFF :{BLACK}Расстояние «Манхэттэн»: {NUM}{}Расстояние по прямой: {NUM}{}Расстояние от ближайшего края: {NUM}{}Высота над уровнем моря: {HEIGHT}{}Разница высот: {HEIGHT} +STR_MEASURE_DIST_HEIGHTDIFF :{BLACK}Манхэттенское расстояние: {NUM}{}Расстояние по прямой: {NUM}{}Расстояние от ближайшего края: {NUM}{}Высота над уровнем моря: {HEIGHT}{}Разница высот: {HEIGHT} STR_SORT_BY_PROFIT_LIFETIME :Пожизненная прибыль STR_SORT_BY_AVG_ORDER_OCCUPANCY :Средняя наполняемость заказа @@ -81,10 +81,10 @@ STR_VEHICLE_TYPE_AIRCRAFT :Авиатра STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL_SPEED :{TINY_FONT}{BLACK}Средняя скорость доставки ({STRING}) STR_GRAPH_CARGO_PAYMENT_RATES_TITLE_AVG_SPEED :{TINY_FONT}{BLACK}Оплата за доставку 1 единицы (или 1000 литров) груза на расстояние 200 квадратов STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL_MINUTES :{TINY_FONT}{BLACK}Минут в пути -STR_GRAPH_STATION_CARGO_CAPTION :{WHITE}{STATION} - История ожидающих грузов +STR_GRAPH_STATION_CARGO_CAPTION :{WHITE}{STATION} - История доступного груза STR_GRAPH_STATION_CARGO_X_LABEL_DAYS :{TINY_FONT}{BLACK}Развитие за последние {NUM} дней STR_GRAPH_STATION_CARGO_X_LABEL_SECONDS :{TINY_FONT}{BLACK}Развитие за последние {NUM} секунд -STR_GRAPH_STATION_CARGO_TITLE :{TINY_FONT}{BLACK}Единицы груза, ожидающие на станции +STR_GRAPH_STATION_CARGO_TITLE :{TINY_FONT}{BLACK}Единицы груза, доступные на станции STR_GRAPH_CARGO_SPEED_MODE :{TINY_FONT}{BLACK}Средняя скорость STR_GRAPH_CARGO_TOOLTIP_TIME_MODE :{BLACK}Отображение времени в пути на оси X графика @@ -102,20 +102,20 @@ STR_SMALLMAP_SCREENSHOT :{BLACK}Скри STR_NEWS_VEHICLE_NO_DEPOT_ORDER :{WHITE}{VEHICLE} не имеет заказа на депо в своем расписании STR_NEWS_TRAIN_OVERSHOT_STATION :{WHITE}{VEHICLE} не смог остановиться в {STRING} из-за чрезмерной скорости -STR_NEWS_ROAD_REBUILDING_PERIODS :{BIG_FONT}{BLACK}Дорожный хаос в {TOWN}!{}{}Программа реконструкции дорог, профинансированая {STRING} принесёт автомобилистам полгода страданий! -STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_PERIOD :{BIG_FONT}{BLACK}Администрация города {TOWN} подписала контракт с {STRING} на 1 период эксклюзивных транспортных прав! +STR_NEWS_ROAD_REBUILDING_PERIODS :{BIG_FONT}{BLACK}Дорожный хаос в городе {TOWN}!{}{}Программа реконструкции дорог, профинансированая компанией {STRING} принесёт автомобилистам полгода страданий! +STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_PERIOD :{BIG_FONT}{BLACK}Администрация города {TOWN} подписала контракт с компанией {STRING} на 1 период эксклюзивных транспортных прав! STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_MINUTES_CUSTOM_LABEL :Пользовательский интервал (минуты реального времени) STR_GAME_OPTIONS_AUTOSAVE_MINUTES_QUERY_CAPT :{WHITE}Интервал автосохранения в минутах реального времени STR_CONFIG_SETTING_ADVISED_LEAVE_DEFAULT :Рекомендуется оставить это значение по умолчанию. -STR_CONFIG_SETTING_TRAIN_BRAKING_REALISTIC :Реалистичная {PUSH_COLOUR}{RED}(Эксперт){POP_COLOUR} +STR_CONFIG_SETTING_TRAIN_BRAKING_REALISTIC :реалистичное {PUSH_COLOUR}{RED}(эксперт){POP_COLOUR} STR_CONFIG_SETTING_TRAIN_BRAKING_ASPECT_LIMITED_ON :На {PUSH_COLOUR}{RED}(Эксперт, Сложно){POP_COLOUR} STR_CONFIG_SETTING_REALISTIC_BRAKING_SIGNALS_NOT_ALLOWED :{WHITE}Реалистичное торможение не может быть включено. Присутствует хотя бы один предварительный или двусторонний сигнал. -STR_CONFIG_SETTING_DELIVERY_BALANCED :Сбалансированная +STR_CONFIG_SETTING_DELIVERY_BALANCED :сбалансированное STR_CONFIG_SETTING_RUNNING_COSTS_IN_DEPOT :Эксплуатационные расходы на транспортные средства в депо: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_IN_DEPOT_HELPTEXT :Установить уровень затрат на техническое обслуживание и эксплуатацию транспортных средств в ожидании в депо (без остановок) @@ -134,8 +134,8 @@ STR_CONFIG_SETTING_RENAME_TOWNS_MULTIPLAYER_HELPTEXT :Если эта STR_CONFIG_SETTING_OVERRIDE_TOWN_SETTINGS_MULTIPLAYER :Позволить многопользовательским клиентам изменять настройки города: {STRING} STR_CONFIG_SETTING_OVERRIDE_TOWN_SETTINGS_MULTIPLAYER_HELPTEXT :Если эта функция включена, то многопользовательские клиенты, не являющиеся администраторами и зрителями, смогут изменять настройки каждого конкретного города. Это всегда доступно в одиночной игре, а также администратору многопользовательского сервера. -STR_CONFIG_SETTING_CATCHMENT_INCREASE :Увеличение зоны покрытия станции: {STRING} -STR_CONFIG_SETTING_CATCHMENT_INCREASE_HELPTEXT :Увеличить зону покрытия станции на указанное количество клеток +STR_CONFIG_SETTING_CATCHMENT_INCREASE :Увеличить охват станции на: {STRING} +STR_CONFIG_SETTING_CATCHMENT_INCREASE_HELPTEXT :Увеличение области, обслуживаемой станцией, на указанное количество клеток. STR_CONFIG_SETTING_STATION_RATING_CARGO_CLASS_WAIT_TIME :Отношение станций к времени ожидания зависит от класса груза: {STRING} STR_CONFIG_SETTING_STATION_RATING_CARGO_CLASS_WAIT_TIME_HELPTEXT:Если включено, то время ожидания с момента последнего получения груза влияет на рейтинг станции для этого груза в зависимости от класса груза. Пассажиры, почта, ценности, рефрижераторные грузы и экспресс-грузы в разной степени менее терпимы к ожиданию. Наливные и жидкие грузы более терпимы. @@ -143,11 +143,11 @@ STR_CONFIG_SETTING_STATION_RATING_CARGO_CLASS_WAIT_TIME_HELPTEXT:Если вкл STR_CONFIG_SETTING_STATION_RATING_SIZE_CARGO_AMOUNT :Вместимость станции и допустимый рейтинг зависят от её размера: {STRING} STR_CONFIG_SETTING_STATION_RATING_SIZE_CARGO_AMOUNT_HELPTEXT :Если включено, то вместимость станций перед ожиданием груза усекается, и влияние количества ожидающего груза на рейтинг станции для этого груза зависит от размера станции. Более крупные станции могут хранить больше грузов и более терпимы к большому количеству ожидающих грузов. -STR_CONFIG_SETTING_CARGO_DELIVERY_MODE :Режим распределения доставки грузов: {STRING} -STR_CONFIG_SETTING_CARGO_DELIVERY_MODE_HELPTEXT :Метод, используемый для доставки грузов на предприятия, расположенные вокруг станции. +STR_CONFIG_SETTING_CARGO_DELIVERY_MODE :Распределение доставленных грузов: {STRING} +STR_CONFIG_SETTING_CARGO_DELIVERY_MODE_HELPTEXT :Каким должно быть распределение прибывших на станцию грузов по предприятиям, расположенным в её зоне охвата. {}«Оригинальное» - распределяет все грузы по ближайшим предприятиям (измеряется от клетки со знаком станции).{}«Сбалансированное» - распределяет грузы поровну между всеми принимающими предприятиями в зоне охвата станции. -STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL :Модель торможения поезда: {STRING} -STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL_HELPTEXT :Выберите физическую модель торможения поезда. "Оригинальное" позволяет поездам останавливаться мгновенно. При "реалистичной" модели у поездов появится тормозной путь, они будут соответствующе резервировать его и не смогут останавливаться мгновенно.{}{}"Реалистичная" Модель имеет множество ограничений для сигнализации и проектирования путей, поэтому является продвинутой функцией, которая может не подойти новичкам. В частности, не допускаются предварительные и двусторонние сигналы, и везде используюся маршрутные семафоры. +STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL :Модель торможения поездов: {STRING} +STR_CONFIG_SETTING_TRAIN_BRAKING_MODEL_HELPTEXT :Настройка физической модели торможения поездов. «Оригинальная» позволяет поездам останавливаться мгновенно. При «реалистичной» модели у поездов появится тормозной путь, они будут соответствующе резервировать его и не смогут останавливаться мгновенно.{}{}«Реалистичная» модель имеет множество ограничений для сигнализации и проектирования путей, поэтому является продвинутой функцией, которая может не подойти новичкам. В частности, не допускаются предварительные и двусторонние сигналы, и везде используюся маршрутные семафоры. STR_CONFIG_SETTING_REALISTIC_BRAKING_ASPECT_LIMITED :Реалистичное торможение поезда ограничено аспектами: {STRING} STR_CONFIG_SETTING_REALISTIC_BRAKING_ASPECT_LIMITED_HELPTEXT :При реалистичной модели торможения поезда ограничить опережающее движение поездов аспектом сигналов (то есть запретить резервировать и опережать неограниченное количество сигналов).{}Для этого необходимы NewGRF, которые обеспечивают многоаспектные сигналы.{}{}Это экспертная настройка, которая, вероятно, повысит сложность игры и потребует дополнительных размышлений о типах и размещении сигналов. @@ -188,8 +188,8 @@ STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :Если вкл STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY :Поезда разных компаний не смогут врезаться друг в друга: {STRING} STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY_HELPTEXT :Эта настройка предназначена в первую очередь для того, чтобы игроки намеренно не вызывали крушения поездов других компаний в многопользовательских играх с совместным использованием железнодорожной инфраструктуры. -STR_CONFIG_SETTING_ROADVEH_ARTICULATED_OVERTAKING :Сочлененные автотранспорты могут совершать обгон: {STRING} -STR_CONFIG_SETTING_ROADVEH_ARTICULATED_OVERTAKING_HELPTEXT :Позволить сочлененным дорожным траспортным средствам обгонять другие. +STR_CONFIG_SETTING_ROADVEH_ARTICULATED_OVERTAKING :Сочленённые автотранспорты могут совершать обгон: {STRING} +STR_CONFIG_SETTING_ROADVEH_ARTICULATED_OVERTAKING_HELPTEXT :Позволить сочленённым дорожным траспортным средствам обгонять другие. STR_CONFIG_SETTING_ROADVEH_CANT_QUANTUM_TUNNEL :Автотранспорты не проходят друг через друга при блокировке: {STRING} STR_CONFIG_SETTING_ROADVEH_CANT_QUANTUM_TUNNEL_HELPTEXT :Запретить проезд одних дорожных транспортных средств через другие, если их путь перекрыт в течение длительного периода времени. @@ -202,10 +202,10 @@ STR_CONFIG_SETTING_WARN_RESTRICTION_WAIT_VEHICLE_HELPTEXT :Запуск с STR_CONFIG_SETTING_WARN_NO_DEPOT_ORDER :Предупреждать, если у транспортного средства нет заказа на депо: {STRING} STR_CONFIG_SETTING_WARN_NO_DEPOT_ORDER_HELPTEXT :Если эта функция включена, а также если включен просмотр заказов на транспортные средства, отправляется сообщение, когда поезд, автотранспорт или судно не имеет заказа на депо в своем расписании. -STR_CONFIG_SETTING_WARN_NO_DEPOT_ORDER_IF_BREAKDOWNS_ON :Если включены поломки транспортных средств +STR_CONFIG_SETTING_WARN_NO_DEPOT_ORDER_IF_BREAKDOWNS_ON :если включены поломки транспортных средств STR_CONFIG_SETTING_NO_EXPIRE_VEHICLES_AFTER :Срок эксплуатации транспортных средств не истекает после: {STRING} -STR_CONFIG_SETTING_NO_EXPIRE_VEHICLES_AFTER_HELPTEXT :Транспортные средства, срок эксплуатации которых закончился бы в этом году, будут доступны всегда.{}Снижение надежности двигателя также прекращается по достижении этого года +STR_CONFIG_SETTING_NO_EXPIRE_VEHICLES_AFTER_HELPTEXT :Транспортные средства, срок эксплуатации которых закончился бы в этом году, будут доступны всегда.{}Снижение надёжности двигателя также прекращается по достижении этого года STR_CONFIG_SETTING_NO_EXPIRE_VEHICLES_AFTER_VALUE :{NUM} STR_CONFIG_SETTING_NO_EXPIRE_VEHICLES_AFTER_ZERO :Отключено @@ -227,12 +227,12 @@ STR_CONFIG_SETTING_SHOW_TRAIN_WEIGHT_RATIOS_IN_DETAILS :Показыв STR_CONFIG_SETTING_SHOW_TRAIN_WEIGHT_RATIOS_IN_DETAILS_HELPTEXT :Демонстрировать соотношение веса поезда в окне сведений о транспортном средстве STR_CONFIG_SETTING_SHOW_RESTRICTED_SIG_RECOLOUR :Отображать сигналы ограничения по умолчанию синими сигнальными столбиками: {STRING} -STR_CONFIG_SETTING_SHOW_RESTRICTED_SIG_RECOLOUR_HELPTEXT :При использовании графики сигналов по умолчанию электрические сигналы с программами ограничения маршрутизации отображаются синим сигнальным столбиком. Не влияет на графику сигналов из NewGRF. Это сделано для того, чтобы легче было визуально различать запрещенные сигналы. +STR_CONFIG_SETTING_SHOW_RESTRICTED_SIG_RECOLOUR_HELPTEXT :При использовании графики сигналов по умолчанию электрические сигналы с программами ограничения маршрутизации отображаются синим сигнальным столбиком. Не влияет на графику сигналов из NewGRF. Это сделано для того, чтобы легче было визуально различать запрещённые сигналы. STR_CONFIG_SETTING_SHOW_ALL_SIG_DEF :Показывать все сигналы, используя графику по умолчанию: {STRING} STR_CONFIG_SETTING_SHOW_ALL_SIG_DEF_HELPTEXT :Показывать все сигналы, используя графику сигналов по умолчанию, вместо любой графики сигналов из NewGRF. Необходимо для того, чтобы было проще определить состояние и тип сигналов, если в NewGRF представлены нечеткие или недоступные сигнальные графики. -STR_CONFIG_SETTING_SHOW_ALL_SIG_DEF_HELPTEXT_EXTRA :{STRING}{}Режим "Только для запрещенных сигналов" использует графику сигналов по умолчанию для электрических сигналов с подключенными программами ограничения маршрутизации, когда перекрашивание сигнальных столбиков включено и NewGRF не обрабатывает различные графики для сигналов с ограничением самостоятельно. -STR_CONFIG_SETTING_SHOW_ALL_SIG_RESTRICTED_RECOLOUR :Только для запрещенных сигналов +STR_CONFIG_SETTING_SHOW_ALL_SIG_DEF_HELPTEXT_EXTRA :{STRING}{}Режим «Только для запрещённых сигналов» использует графику сигналов по умолчанию для электрических сигналов с подключенными программами ограничения маршрутизации, когда перекрашивание сигнальных столбиков включено и NewGRF не обрабатывает различные графики для сигналов с ограничением самостоятельно. +STR_CONFIG_SETTING_SHOW_ALL_SIG_RESTRICTED_RECOLOUR :Только для запрещённых сигналов STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES :Показывать расширенные функции ограничения маршрутизации: {STRING} STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES_HELPTEXT :Показывать расширенные возможности ограничения маршрутизации. Если отключено, то некоторые расширенные возможности не будут отображаться в пользовательском интерфейсе, но останутся доступными всем игрокам. @@ -249,8 +249,8 @@ STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES_HELPTEXT :Показыв STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS :Отключить кнопки массовых действий для списков транспортных средств верхнего уровня: {STRING} STR_CONFIG_SETTING_DISABLE_TOP_VEH_LIST_MASS_ACTIONS_HELPTEXT :Отключить депо/сервис и кнопки запуска/остановки для всех транспортных средств и всех негруппированных списков транспортных средств. Это сделано для того, чтобы избежать негативных последствий случайного нажатия одной из этих кнопок. -STR_CONFIG_SETTING_SHOW_DEPOT_SELL_GUI :Отображать функцию "отправить в депо/ангар и продать": {STRING} -STR_CONFIG_SETTING_SHOW_DEPOT_SELL_GUI_HELPTEXT :Отображать функцию для отправки транспортного средства в депо/ангар с последующей продажей. Если включено, то Ctrl+щелчок по кнопке "Перейти в депо" в окне транспортного средства позволит изменить режим работы текущего заказ на депо. +STR_CONFIG_SETTING_SHOW_DEPOT_SELL_GUI :Отображать функцию «отправить в депо/ангар и продать»: {STRING} +STR_CONFIG_SETTING_SHOW_DEPOT_SELL_GUI_HELPTEXT :Отображать функцию для отправки транспортного средства в депо/ангар с последующей продажей. Если включено, то Ctrl+щелчок по кнопке «Перейти в депо» в окне транспортного средства позволит изменить режим работы текущего заказ на депо. STR_CONFIG_SETTING_OPEN_VEHICLE_GUI_CLONE_SHARE :Открывать окно нового транспортного средства при клонировании с общими заказами: {STRING} STR_CONFIG_SETTING_OPEN_VEHICLE_GUI_CLONE_SHARE_HELPTEXT :Если включено, то при клонировании транспортного средства с общими заказами из окна депо открывается окно нового клонированного транспортного средства. @@ -276,7 +276,7 @@ STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW_HELPTEXT :Если вкл STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW_DUAL_BUTTONS :Отображать отдельные наборы кнопок в окне покупки поезда: {STRING} STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW_DUAL_BUTTONS_HELPTEXT:Если включено, то списки вагонов и локомотивов в окне покупки поездов будут иметь свой собственный набор кнопок. -STR_CONFIG_SETTING_ALLOW_HIDE_WAYPOINT_LABEL :Разрешить скрывать метки в окне просмотра путевых точек: {STRING} +STR_CONFIG_SETTING_ALLOW_HIDE_WAYPOINT_LABEL :Скрывать метки в окне просмотра путевых точек: {STRING} STR_CONFIG_SETTING_ALLOW_HIDE_WAYPOINT_LABEL_HELPTEXT :Если включено, то ярлыки путевых точек могут быть скрыты по отдельности.{}Полезно, когда незначительные путевые точки не требуют обозначения или путевые точки используются декоративно. STR_CONFIG_SETTING_DISABLE_WATER_ANIMATION :Отключить анимацию воды: {STRING} @@ -313,9 +313,9 @@ STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR :Показыв STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR_HELPTEXT :При использовании коэффициента продолжительности дня больше единицы, показывать эксплуатационные расходы транспортного средства за календарный год (в режиме календаря) или за период (в режиме реального времени), а не за оригинальный год. STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Включить сигналы на мостах/туннелях в расширенных режимах: {STRING} -STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT :Включить использование расширенного режима моделирования сигналов на мостах и в туннелях. Если отключено, то мосты/туннели, которые еще не находятся в расширенном режиме, не смогут быть переведены в него, однако другие игроки могут включить этот параметр и использовать расширенный режим. +STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT :Включить использование расширенного режима моделирования сигналов на мостах и в туннелях. Если отключено, то мосты/туннели, которые ещё не находятся в расширенном режиме, не смогут быть переведены в него, однако другие игроки могут включить этот параметр и использовать расширенный режим. -STR_CONFIG_SETTING_SORT_TRACK_TYPES_BY_SPEED :Сортировать типов дорожек по скорости: {STRING} +STR_CONFIG_SETTING_SORT_TRACK_TYPES_BY_SPEED :Сортировать типы дорожек по скорости: {STRING} STR_CONFIG_SETTING_SORT_TRACK_TYPES_BY_SPEED_HELPTEXT :Сортировать типы дорожек по совместимости и по скорости вместо сортировки по умолчанию. STR_CONFIG_SETTING_MAX_SIGNAL_EVALUATIONS :Максимальное количество программируемых изменений предварительного сигнала, разрешенных одновременно: {STRING} @@ -412,7 +412,7 @@ STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE_HELPTEXT :Режим от STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK :Функция двойного клика: {STRING} STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_HELPTEXT :Какое действие следует выполнять при двойном щелчке на окне просмотра при уменьшении масштаба в режиме карты. STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_DO_NOTHING :Ничего не делать -STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_ZOOM_MAIN :Увеличьте масштаб прямо на 1x +STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_ZOOM_MAIN :Увеличить масштаб прямо на 1x STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_NEW_EXTRA :Открыть дополнительное окно просмотра STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE :Показывать линии наложения маршрутов транспортных средств: {STRING} @@ -463,10 +463,10 @@ STR_CONFIG_SETTING_DATE_WITH_TIME_HELPTEXT :Показыв STR_CONFIG_SETTING_CLOCK_OFFSET :Смещение часов в минутах: {STRING} STR_CONFIG_SETTING_CLOCK_OFFSET_HELPTEXT :Количество минут, на которое смещены игровые часы -STR_CONFIG_SETTING_DATE_WITH_TIME_NONE :Нет -STR_CONFIG_SETTING_DATE_WITH_TIME_Y :Год -STR_CONFIG_SETTING_DATE_WITH_TIME_YM :Месяц и год -STR_CONFIG_SETTING_DATE_WITH_TIME_YMD :Полная дата +STR_CONFIG_SETTING_DATE_WITH_TIME_NONE :нет +STR_CONFIG_SETTING_DATE_WITH_TIME_Y :год +STR_CONFIG_SETTING_DATE_WITH_TIME_YM :месяц и год +STR_CONFIG_SETTING_DATE_WITH_TIME_YMD :полная дата STR_CONFIG_SETTING_TIMETABLE_START_TEXT_ENTRY :Введите время начала расписания в виде текста (необходимо указать время в минутах): {STRING} STR_CONFIG_SETTING_TIMETABLE_START_TEXT_ENTRY_HELPTEXT :Выберите, можно ли вводить время начала расписания в виде текста, если время показывается в минутах. @@ -487,7 +487,7 @@ STR_CONFIG_SETTING_SCHEDULED_DISPATCH_DEFAULT_DURATION_VALUE :{COMMA}{NBSP}м STR_CONFIG_SETTING_SCHEDULED_DISPATCH_DEFAULT_DURATION_DEFAULT :По умолчанию STR_CONFIG_SETTING_DEFAULT_ROAD_TYPE :Типы дорог/трамвайных путей по умолчанию (после запуска новой игры/загрузки): {STRING} -STR_CONFIG_SETTING_DEFAULT_ROAD_TYPE_HELPTEXT :Выбор типа дороги/трамвайных путей после запуска новой игры или загрузки старой. 'первые доступные' выбирает самый старый тип дороги/трамвайного пути, 'последние доступные' выбирает самый новый тип дороги/трамвайного пути, 'наиболее используемые' выбирает тип, который наиболее часто используется в настоящее время, и 'по умолчанию' выбирает тип по умолчанию. +STR_CONFIG_SETTING_DEFAULT_ROAD_TYPE_HELPTEXT :Выбор типа дороги/трамвайных путей после запуска новой игры или загрузки старой. «Первые доступные» выбирает самый старый тип дороги/трамвайного пути, «последние доступные» выбирает самый новый тип дороги/трамвайного пути, «наиболее используемые» выбирает тип, который наиболее часто используется в настоящее время, и «по умолчанию» выбирает тип по умолчанию. STR_CONFIG_SETTING_ENABLE_BUILD_RIVER :Включить строительство рек: {STRING} STR_CONFIG_SETTING_ENABLE_BUILD_RIVER_HELPTEXT :Разрешить прокладывать реки не только в редакторе сценариев @@ -508,10 +508,10 @@ STR_CONFIG_SETTING_SHARING_PAYMENT_IN_DEBT :Разреши STR_CONFIG_SETTING_SHARING_USED_BY_VEHICLES :Невозможно изменить этот параметр - транспортные средства используют инфраструктуру чужих компаний. STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS :Невозможно изменить этот параметр - у транспортных средств есть задания с пунктами назначения в инфраструктуре чужих компаний. -STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_RAIL :Позволять конкурентам покупать и обновлять поезда в депо: {STRING} -STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_ROAD :Позволить конкурентам покупать и обновлять автотранспорт в депо: {STRING} -STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_WATER :Позволить конкурентам покупать и обновлять корабли в депо: {STRING} -STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_AIR :Позволить конкурентам покупать и обновлять авиатранспорт в ангарах: {STRING} +STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_RAIL :Конкуренты могут покупать и обновлять поезда в депо: {STRING} +STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_ROAD :Конкуренты могут покупать и обновлять автотранспорт в депо: {STRING} +STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_WATER :Конкуренты могут покупать и обновлять корабли в депо: {STRING} +STR_CONFIG_SETTING_INFRA_OTHERS_BUY_IN_DEPOT_AIR :Конкуренты могут покупать и обновлять авиатранспорт в ангарах: {STRING} STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION :Включить адаптацию скорости поезда: {STRING} STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION_HELPTEXT :Если включено, более быстрые поезда регулируют свою скорость, чтобы соответствовать более медленным поездам впереди. @@ -523,7 +523,7 @@ STR_CONFIG_SETTING_SIMULATE_SIGNALS :Симуляц STR_CONFIG_SETTING_SIMULATE_SIGNALS_HELPTEXT :Устанавливает целевое расстояние между светофорами для новых мостов и туннелей. Фактическое расстояние может немного отличаться от указанного, чтобы избежать неравномерного расположения. Изменение этого параметра не приводит к переоборудованию существующих мостов и туннелей со светофорами. STR_CONFIG_SETTING_SIMULATE_SIGNALS_VALUE :{COMMA} клет{P ку ки ок} -STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Коэффициент продолжительности дня: {STRING} +STR_CONFIG_SETTING_DAY_LENGTH_FACTOR :Фактор продолжительности дня: {STRING} STR_CONFIG_SETTING_DAY_LENGTH_FACTOR_HELPTEXT :Темп игры замедляется из-за этого фактора. STR_CONFIG_SETTING_TOWN_TUNNELS :Строительство тоннелей городами: {STRING} @@ -541,13 +541,13 @@ STR_CONFIG_SETTING_TOWN_MAX_ROAD_SLOPE_ZERO :Нет STR_CONFIG_SETTING_ALLOW_TOWN_BRIDGES :Города могут строить мосты: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_BRIDGES_HELPTEXT :Включение этой настройки разрешает городам строить мосты -STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_HELPTEXT_EXTRA :{STRING}{}Сюда не входят предприятия, занимающиеся вырубкой деревьев.{}Не гарантируется полная совместимость со всеми NewGRFs с предприятиями. +STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_HELPTEXT_EXTRA :{STRING}{}Не действует на предприятия, занимающиеся вырубкой деревьев.{}Не гарантируется полная совместимость со всеми NewGRF предприятиями. -STR_CONFIG_SETTING_TOWN_CARGO_SCALE_MODE :Временной интервал для масштабирования производства грузов городов: {STRING} -STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_MODE :Временной интервал для масштабирования производства грузов предприятий: {STRING} +STR_CONFIG_SETTING_TOWN_CARGO_SCALE_MODE :Временной интервал для умножения производства грузов городами: {STRING} +STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_MODE :Временной интервал для умножения производства грузов предприятиями: {STRING} -STR_CONFIG_SETTING_CARGO_SCALE_MODE_HELPTEXT :Ежемесячно/каждый производственный интервал: Производство груза за месяц или производственный интервал масштабируется.{}{}Игровое время: производство груза за единицу игрового времени масштабируется, (производство груза за месяц или производственный интервал также масштабируется коэффициентом продолжительности дня). Очень высокие коэффициенты масштабирования могут быть недостижимы. -STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_MODE_HELPTEXT_EXTRA :{STRING}{}Не гарантируется, что режим игрового времени будет полностью совместим со всеми NewGRFs с предприятиями. +STR_CONFIG_SETTING_CARGO_SCALE_MODE_HELPTEXT :Ежемесячно/каждый производственный интервал: производство груза за месяц или производственный интервал умножается.{}{}Игровое время: производство груза за единицу игрового времени умножается, (производство груза за месяц или производственный интервал также умножается коэффициентом продолжительности дня). Очень высокие коэффициенты умножения могут быть недостижимы. +STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_MODE_HELPTEXT_EXTRA :{STRING}{}Не гарантируется, что режим игрового времени будет полностью совместим со всеми NewGRF предприятиями. STR_CONFIG_SETTING_CARGO_SCALE_MODE_MONTHLY :Ежемесячно STR_CONFIG_SETTING_CARGO_SCALE_MODE_GAME_TIME :Игровое время @@ -563,10 +563,10 @@ STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT :Никаких STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT_HELPTEXT :Во время создания карты не строятся города выше указанного уровня высоты. STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA :Минимальная площадь прилегающей территории для городов: {STRING} -STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA_HELPTEXT :Города могут быть размещены только на смежных территориях, занимающих как минимум столько клеток. +STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA_HELPTEXT :Города могут быть размещены только на примыкающих территориях, занимающих как минимум столько клеток. STR_CONFIG_SETTING_MIN_CITY_LAND_AREA :Минимальная площадь прилегающей территории для мегаполисов: {STRING} -STR_CONFIG_SETTING_MIN_CITY_LAND_AREA_HELPTEXT :Мегаполисы могут быть размещены только на смежных территориях, занимающих как минимум столько клеток. +STR_CONFIG_SETTING_MIN_CITY_LAND_AREA_HELPTEXT :Мегаполисы могут быть размещены только на примыкающих территориях, занимающих как минимум столько клеток. STR_CONFIG_SETTING_MIN_LAND_AREA_VALUE :{NUM} STR_CONFIG_SETTING_MIN_LAND_AREA_ZERO :Отсутсвует @@ -574,7 +574,7 @@ STR_CONFIG_SETTING_MIN_LAND_AREA_ZERO :Отсутсв STR_CONFIG_SETTING_FLOOD_FROM_EDGES :Вода заливает края карты: {STRING} STR_CONFIG_SETTING_FLOOD_FROM_EDGES_HELPTEXT :Заливает ли вода крайние плитки на уровне моря от края карты. -STR_CONFIG_SETTING_MAP_EDGE_MODE :Поведение краёв карты: {STRING} +STR_CONFIG_SETTING_MAP_EDGE_MODE :Режим краёв карты: {STRING} STR_CONFIG_SETTING_MAP_EDGE_MODE_HELPTEXT :Разрешается ли поднимать края карты над уровнем моря и как отображается пустота за пределами карты STR_CONFIG_SETTING_MAP_EDGE_MODE_DEFAULT :По умолчанию STR_CONFIG_SETTING_MAP_EDGE_MODE_SEA_LEVEL :Края карты ограничены уровнем моря @@ -588,7 +588,7 @@ STR_CONFIG_SETTING_TREES_AROUND_SNOWLINE_DYNAMIC_RANGE :Сезонна STR_CONFIG_SETTING_TREES_AROUND_SNOWLINE_DYNAMIC_RANGE_HELPTEXT :При использовании сезонно изменяющейся снеговой линии, какой процент от вариации снеговой линии использовать в качестве снеговой линии для размещения арктических деревьев. 0% использует нижнюю (зимнюю) снеговую линию, 100% использует весь диапазон между летней и зимней снеговыми линиями. STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS :Построить общественные дороги, соединяющие города: {STRING} -STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS_HELPTEXT :Создаёт общественные дороги, соединяющие города. Занимает некоторое время на больших картах. 'Строить без изгибов' генерирует дороги, которые избегают изгибы и создают соединения, очень похожие на сетку. +STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS_HELPTEXT :Создаёт общественные дороги, соединяющие города. Занимает некоторое время на больших картах. «Строить без изгибов» генерирует дороги, которые избегают изгибы и создают соединения, очень похожие на сетку. STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS_NONE :Нет (по умолчанию) STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS_WITH_CURVES :Строить с изгибами STR_CONFIG_SETTING_BUILD_PUBLIC_ROADS_AVOID_CURVES :Стройть без изгибов @@ -646,9 +646,9 @@ STR_CONFIG_SETTING_TOWN_MIN_DISTANCE_HELPTEXT :Устанав STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO :Переопределение режима распределения для этого груза: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_PARAM :Переопределение режима распределения для {STRING}: {STRING} -STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT :"(по умолчанию)" означает, что режим распределения является стандартным для класса этого груза. "симметричный" означает, что со станции А на станцию Б будет отправлено примерно столько же грузов, сколько со станции Б на А. "асимметричный" означает, что произвольное количество груза может быть отправлено в любом направлении. "ручной" означает, что для этого груза не будет проводиться автоматическое распределение. +STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT :«(по умолчанию)» означает, что режим распределения является стандартным для класса этого груза. «симметричный» означает, что со станции А на станцию Б будет отправлено примерно столько же грузов, сколько со станции Б на А. «асимметричный» означает, что произвольное количество груза может быть отправлено в любом направлении. «ручной» означает, что для этого груза не будет проводиться автоматическое распределение. STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_DEFAULT :(по умолчанию) -STR_CONFIG_SETTING_DISTRIBUTION_HELPTEXT_EXTRA :{STRING}{}"асимметричный (равномерное распределение)" означает, что груз будет распределен таким образом, что каждая принимающая станция получит примерно одинаковое количество груза в целом. "асимметричный (ближайший)" означает, что груз будет отправляться на ту станцию, которая находится ближе всего. +STR_CONFIG_SETTING_DISTRIBUTION_HELPTEXT_EXTRA :{STRING}{}«Асимметричный (равномерное распределение)» означает, что груз будет распределен таким образом, что каждая принимающая станция получит примерно одинаковое количество груза в целом. «Асимметричный (ближайший)» означает, что груз будет отправляться на ту станцию, которая находится ближе всего. STR_CONFIG_SETTING_AIRCRAFT_PATH_COST :Масштаб расстояния путей, на которых используется авиатранспорт: {STRING} STR_CONFIG_SETTING_AIRCRAFT_PATH_COST_HELPTEXT :Увеличивает стоимость (метрику расстояния) путей, использующих авиатранспорт, так что они кажутся более длинными/менее прямыми, чем есть на самом деле. Снижает вероятность того, что прямые маршруты с использованием самолетов окажутся сильно перегруженными. @@ -672,14 +672,14 @@ STR_CONFIG_SETTING_SHARING :{ORANGE}Сов STR_CONFIG_SETTING_SCENARIO_EDITOR :{ORANGE}Редактор сценариев STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE :Изменять маршрут движения автотранспорта при изменении планировки дороги: {STRING} -STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_HELPTEXT :Нужно ли изменять маршрут всех автотранспортных средств на карте при изменении схемы дорог.{}Это может повысить скорость реагирования автотранспорта на изменение планировки дороги за счет снижения производительности.{}Обратите внимание, что если установить значение "Да", то рост города может вызвать изменение маршрута движения транспорта, что может привести к замедлению работы на больших картах. +STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_HELPTEXT :Нужно ли изменять маршрут всех автотранспортных средств на карте при изменении схемы дорог.{}Это может повысить скорость реагирования автотранспорта на изменение планировки дороги за счет снижения производительности.{}Обратите внимание, что если установить значение «Да», то рост города может вызвать изменение маршрута движения транспорта, что может привести к замедлению работы на больших картах. STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_NO :Нет STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_REMOVE_ONLY :Только при удалении дорог STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_YES :Да -STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS :Включить настриваемые опоры дорожных мостов: {STRING} +STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS :Включить настраиваемые опоры дорожных мостов: {STRING} STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT :Позволяет дорожным мостам иметь пользовательские, непрямые плоские клетки для въезда/выезда -STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS :Включить настриваемые опоры железнодорожных мостов: {STRING} +STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS :Включить настраиваемые опоры железнодорожных мостов: {STRING} STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS_HELPTEXT :Позволяет железнодорожным мостам иметь нестандартные, непрямые плоские клетки для въезда/выезда STR_CONFIG_SETTING_ALLOW_GRF_OBJECTS_UNDER_BRIDGES :Разрешить все объекты NewGRF под мостами: {STRING} @@ -712,7 +712,7 @@ STR_CONFIG_SETTING_IGNORE_OBJECT_INTRO_DATES_HELPTEXT :Установ STR_CONFIG_SETTING_ALLOW_CONVERT_TOWN_ROAD_NO_HOUSES :Разрешить переоборудование городских дорог под дороги, не предназначенные для жилых домов: {STRING} STR_CONFIG_SETTING_ALLOW_CONVERT_TOWN_ROAD_NO_HOUSES_HELPTEXT :Могут ли игроки переводить дороги, принадлежащие городу, в тип дороги, не позволяющий строить дома.{}По умолчанию - отключено, поскольку может помешать городам строить дома, что приведет к уменьшению городов. -STR_CONFIG_SETTING_PURCHASED_LAND_CLEAR_GROUND :Использовать чисткю клетку грунта для приобретенной земли: {STRING} +STR_CONFIG_SETTING_PURCHASED_LAND_CLEAR_GROUND :Использовать чистую клетку грунта для приобретенной земли: {STRING} STR_CONFIG_SETTING_PURCHASED_LAND_CLEAR_GROUND_HELPTEXT :Если эта функция включена, то купленная земля будет отображаться с использованием того же типа грунта, что и клетки чистой земли, то емть голая земля - трава, побережье, снег, пустыня и так далее. STR_CONFIG_SETTING_SPAWN_PRIMARY_INDUSTRY_ONLY :Генерировать только сырьевые предприятия: {STRING} @@ -751,7 +751,7 @@ STR_CONFIG_SETTING_COPY_CLONE_ADD_TO_GROUP_HELPTEXT :Установ STR_CONFIG_SETTING_REMAIN_IF_NEXT_ORDER_SAME_STATION :Остаться на станции, если следующее задание касается той же станции: {STRING} STR_CONFIG_SETTING_REMAIN_IF_NEXT_ORDER_SAME_STATION_HELPTEXT :Если следующее задание транспортного средства относится к той же станции, с которой оно собиралось уехать, начать погрузку/разгрузку снова, а не уезжать. -STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS :Разрешить множественные церкви/стадионы: {STRING} +STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS :Разрешить несколько церквей/стадионов: {STRING} STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS_HELPTEXT :Позволяет вручную добавлять церкви и стадионы, если они уже есть в городе. STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_DATES :Игнорировать ограничения года постройки дома: {STRING} @@ -779,15 +779,15 @@ STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Время пу STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT_EXTRA :{STRING}{}Различные функции требуют использования алгоритма поиска пути YAPF, в том числе: ограничения маршрута (все действия, связанные с поиском пути и резервированием), разворот на маршрутной точке/светофоре и проезд через железнодорожные депо. -STR_CONFIG_SETTING_DISABLED_TIMEKEEPING_MODE_CALENDAR :{RED}[Настройка отсключена при системе отчёта времени "Календарь"] -STR_CONFIG_SETTING_DISABLED_TIMEKEEPING_MODE_WALLCLOCK :{RED}[Настройка отсключена при системе отчёта времени "Реальное время"] +STR_CONFIG_SETTING_DISABLED_TIMEKEEPING_MODE_CALENDAR :{RED}[Настройка отсключена при системе отчёта времени «Календарь»] +STR_CONFIG_SETTING_DISABLED_TIMEKEEPING_MODE_WALLCLOCK :{RED}[Настройка отсключена при системе отчёта времени «Реальное время»] STR_CHEAT_EDIT_MONEY_QUERY_CAPT :{WHITE}Увеличить или уменьшить количество денег STR_CHEAT_INFLATION_COST :{LTBLUE}Изменение уровня инфляции: {ORANGE}{DECIMAL} STR_CHEAT_INFLATION_COST_QUERY_CAPT :{WHITE}Изменение уровня инфляции STR_CHEAT_INFLATION_INCOME :{LTBLUE}Изменение уровня инфляции доходов: {ORANGE}{DECIMAL} STR_CHEAT_INFLATION_INCOME_QUERY_CAPT :{WHITE}Изменение уровня инфляции доходов -STR_CHEAT_TOWN_RATING :{LTBLUE}Рейтинг у городской администрации зафиксирован на "Великолепном" уровне: {ORANGE}{STRING} +STR_CHEAT_TOWN_RATING :{LTBLUE}Рейтинг у городской администрации зафиксирован на «Великолепном» уровне: {ORANGE}{STRING} STR_NETWORK_MESSAGE_GIVE_MONEY_RECEIVE :*** {STRING} даёт вашей компании {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Вы дали {1:STRING} {2:CURRENCY_LONG} @@ -835,7 +835,7 @@ STR_TRACE_RESTRICT_VARIABLE_TRAIN_LENGTH :длина по STR_TRACE_RESTRICT_VARIABLE_MAX_SPEED :максимальная скорость STR_TRACE_RESTRICT_VARIABLE_CURRENT_ORDER :текущее задание STR_TRACE_RESTRICT_VARIABLE_NEXT_ORDER :следующее задание -STR_TRACE_RESTRICT_VARIABLE_LAST_VISITED_STATION :последняя посещенная станция +STR_TRACE_RESTRICT_VARIABLE_LAST_VISITED_STATION :последняя посещённая станция STR_TRACE_RESTRICT_VARIABLE_CARGO :груз STR_TRACE_RESTRICT_VARIABLE_LOAD_PERCENT :процент загрузки STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION :направление входа @@ -1096,8 +1096,8 @@ STR_TRACE_RESTRICT_ERROR_VALUE_TOO_LARGE :{WHITE}Знач STR_TRACE_RESTRICT_ERROR_NO_PROGRAM :Нет программы STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE :Слишком большое смещение STR_TRACE_RESTRICT_ERROR_CAN_T_CHANGE_CONDITIONALITY :Невозможно изменить условия -STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF :Невозможно удалить 'конец если' -STR_TRACE_RESTRICT_ERROR_CAN_T_SHALLOW_REMOVE_IF_ELIF :Нельзя неглубоко удалить блок 'если' с одним или несколькими блоками 'иначе если', 'или если' или 'иначе'. +STR_TRACE_RESTRICT_ERROR_CAN_T_REMOVE_ENDIF :Невозможно удалить «конец если» +STR_TRACE_RESTRICT_ERROR_CAN_T_SHALLOW_REMOVE_IF_ELIF :Нельзя неглубоко удалить блок «если» с одним или несколькими блоками «иначе если», «или если» или «иначе». STR_TRACE_RESTRICT_ERROR_VALIDATE_END_CONDSTACK :Проверка не удалась: кондстек не пуст при выходе STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF :Проверка не удалась: иначе/конец если без открывающего если STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE :Проверка не удалась: дублирующийся иначе @@ -1238,7 +1238,7 @@ STR_TREES_REMOVE_TREES_TOOLTIP :{BLACK}Удал STR_TERRAFORM_PUBLIC_ROADS :{BLACK}Построить общественные дороги STR_TERRAFORM_PUBLIC_ROADS_TOOLTIP :{BLACK}Создать общественные дороги между городами на карте -STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_ALL :Все предпрятия +STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_ALL :Все предприятия STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PROGSIGNALS :Железнодорожный путь с программируемыми пресигналами STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRY2SIGNALS :Железнодорожный путь с невходящими сигналами @@ -1313,7 +1313,7 @@ STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY :Нереали STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_ACTION5_TYPE :Нереализованный тип ремаппинга Action 5: название: {2:STRING}, сопоставленный с: {4:HEX} (спрайт {3:NUM}) STR_NEWGRF_TOO_MANY_STRINGS :{WHITE}Недостаточно идентификаторов строк для всех NewGRF. -STR_NEWGRF_TOO_MANY_STRINGS_DETAIL :{WHITE}Некоторые имена и текстовые поля могут отображаться некорректно. Попробуйте использовать меньше NewGRFs. +STR_NEWGRF_TOO_MANY_STRINGS_DETAIL :{WHITE}Некоторые имена и текстовые поля могут отображаться некорректно. Попробуйте использовать меньше модулей NewGRF. STR_TOWN_VIEW_NOISE_IN_TOWN_NO_LIMIT :{BLACK}Предельный уровень шума в городе: {ORANGE}{COMMA} @@ -1821,8 +1821,8 @@ STR_TIMETABLE_NON_TIMETABLED_BRANCH :{BLACK}Не в STR_TIMETABLE_WARNING_NO_SCHEDULED_DISPATCH_ORDER_ASSIGNED :{BLACK}Расписание отправки не назначено для задания STR_TIMETABLE_WARNING_SCHEDULED_DISPATCH_ORDER_NO_WAIT_TIME :{BLACK}Запланированное задание на отправку должено иметь установленное время ожидания STR_TIMETABLE_WARNING_SCHEDULE_ID :{BLACK}Расписание {NUM}: {STRING} -STR_TIMETABLE_FILL_TIMETABLE_SUGGESTION :{BLACK}Включить 'Автоматически' для автоматического заполнения и обновления времени ожидания и поездок. -STR_TIMETABLE_FILL_TIMETABLE_SUGGESTION_2 :{BLACK}(Альтернативно, включить 'Автозаполнение' или вручную заполнить все поля расписания). +STR_TIMETABLE_FILL_TIMETABLE_SUGGESTION :{BLACK}Включить «Автоматически» для автоматического заполнения и обновления времени ожидания и поездок. +STR_TIMETABLE_FILL_TIMETABLE_SUGGESTION_2 :{BLACK}(Альтернативно, включить «Автозаполнение» или вручную заполнить все поля расписания). STR_TIMETABLE_WARNINGS_OMITTED :{BLACK}{NUM} дальнейшие предупреждения опущены... @@ -1883,8 +1883,8 @@ STR_PLANS_QUERY_RENAME_PLAN :{WHITE}Пере STR_WARNING_LOADGAME_REMOVED_UNCORRECTABLE_VEHICLES :{WHITE}Удалено {NUM} транспорт{P "" а ов}, которые были признаны некорректными во время загрузки STR_GAME_SAVELOAD_FROM_VERSION : из версии {PUSH_COLOUR}{ORANGE}{STRING}{POP_COLOUR}{} -STR_GAME_SAVELOAD_ERROR_TOO_NEW_FEATURE_VERSION :Сохранение{0:STRING} имеет версию {PUSH_COLOUR}{ORANGE}{2:NUM}{POP_COLOUR} особенности '{PUSH_COLOUR}{ORANGE}{1:STRING}{POP_COLOUR}', но максимальная поддерживаемая версия - {PUSH_COLOUR}{ORANGE}{3:NUM}{POP_COLOUR} -STR_GAME_SAVELOAD_ERROR_UNKNOWN_FEATURE :Сохранение{0:STRING} имеет неизвестную особенность '{PUSH_COLOUR}{ORANGE}{1:STRING}{POP_COLOUR}' (версия: {PUSH_COLOUR}{ORANGE}{2:NUM}{POP_COLOUR}), которая не поддерживается +STR_GAME_SAVELOAD_ERROR_TOO_NEW_FEATURE_VERSION :Сохранение{0:STRING} имеет версию {PUSH_COLOUR}{ORANGE}{2:NUM}{POP_COLOUR} особенности «{PUSH_COLOUR}{ORANGE}{1:STRING}{POP_COLOUR}», но максимальная поддерживаемая версия - {PUSH_COLOUR}{ORANGE}{3:NUM}{POP_COLOUR} +STR_GAME_SAVELOAD_ERROR_UNKNOWN_FEATURE :Сохранение{0:STRING} имеет неизвестную особенность «{PUSH_COLOUR}{ORANGE}{1:STRING}{POP_COLOUR}» (версия: {PUSH_COLOUR}{ORANGE}{2:NUM}{POP_COLOUR}), которая не поддерживается STR_GAME_SAVELOAD_ERROR_HUGE_AIRPORTS_PRESENT :В сохранении используются огромные аэропорты STR_GAME_SAVELOAD_ERROR_HELI_OILRIG_BUG :В сохранении вертолёт приближается к багованой нефтяной вышке @@ -1971,7 +1971,7 @@ STR_ZONING_NO_ZONING :Ничего STR_ZONING_AUTHORITY :Администрация STR_ZONING_CAN_BUILD :Где я не могу строить STR_ZONING_STA_CATCH :Охват станции -STR_ZONING_STA_CATCH_OPEN :Охват станции станции (window open) +STR_ZONING_STA_CATCH_OPEN :Охват станции станции (окно открыто) STR_ZONING_BUL_UNSER :Необслуживаемые здания STR_ZONING_IND_UNSER :Необслуживаемые предприятия STR_ZONING_TRACERESTRICT :Запрещённые сигналы @@ -2095,7 +2095,7 @@ STR_TMPL_RPLALLGUI_INSET_BOTTOM :{BLACK}Теку STR_TMPL_RPLALLGUI_BUTTON_RPLALL :{BLACK}Заменить всё STR_TMPL_RPLALLGUI_BUTTON_APPLY :{BLACK}Применить STR_TMPL_RPLALLGUI_BUTTON_CANCEL :{BLACK}Отмена -STR_TMPL_RPLALLGUI_USE_TIP :{BLACK}Выберите тип транспортного средства из каждого списка и нажмите 'Заменить всё'. Если вас устраивает результат, отображаемый в списке шаблонов, нажмите 'Применить' чтобы реально применить эти изменения. +STR_TMPL_RPLALLGUI_USE_TIP :{BLACK}Выберите тип транспортного средства из каждого списка и нажмите «Заменить всё». Если вас устраивает результат, отображаемый в списке шаблонов, нажмите «Применить» чтобы реально применить эти изменения. STR_TMPL_CANT_CREATE :{WHITE}Невозможно создать шаблон или виртуальное транспортное средство... STR_TMPL_CANT_RENAME :{WHITE}Невозможно переименовать шаблон... @@ -2237,7 +2237,7 @@ STR_REFIT_SHIP_PART :Часть {NUM STR_VERY_REDUCED :очень сниженная -STR_STATION_VIEW_RENAME_TOOLTIP_EXTRA :{BLACK}{STRING}{}(Ctrl+клик "{STRING}" чтобы сгенерировать новое имя по умолчанию).{}{}Ctrl+клик - обменяться названиями с другой станцией. +STR_STATION_VIEW_RENAME_TOOLTIP_EXTRA :{BLACK}{STRING}{}(Ctrl+клик «{STRING}» чтобы сгенерировать новое имя по умолчанию).{}{}Ctrl+клик - обменяться названиями с другой станцией. STR_ERROR_CAN_T_EXCHANGE_STATION_NAMES :{WHITE}Невозможно обменяться названиями станций... STR_ERROR_STATIONS_NOT_IN_SAME_TOWN :{WHITE}... станции находятся в разных городах STR_ERROR_STATION_ATTACHED_TO_INDUSTRY :{WHITE}... станция прикреплена к предприятию From 07afb0e00bedbc65b10530a3a62f5582db082d41 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 00:18:42 +0100 Subject: [PATCH 077/107] Saveload: Remove incorrect table mode check in Save_DBGD --- src/sl/debug_sl.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sl/debug_sl.cpp b/src/sl/debug_sl.cpp index 7eb603eb5e..75e26bdf55 100644 --- a/src/sl/debug_sl.cpp +++ b/src/sl/debug_sl.cpp @@ -63,11 +63,6 @@ static void Check_DBGC() static void Save_DBGD() { - if (!SlIsTableChunk()) { - SlSkipChunkContents(); - return; - } - std::vector nsl; if (_save_DBGC_data) { extern std::string _config_file_text; From 10c136f039ea3e7bd0b977c20932532ec41243e4 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 00:49:37 +0100 Subject: [PATCH 078/107] Saveload: Add mechanism for custom handling of missing table fields --- src/sl/saveload.cpp | 4 +++- src/sl/saveload.h | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 43a1fdc1cf..7f85345a47 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2208,7 +2208,7 @@ static uint8_t GetSavegameTableFileType(const SaveLoad &sld) * @param slt The NamedSaveLoad table with objects to save/load. * @return The ordered SaveLoad array to use. */ -std::vector SlTableHeader(const NamedSaveLoadTable &slt) +std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler) { /* You can only use SlTableHeader if you are a CH_TABLE. */ assert(_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); @@ -2255,6 +2255,8 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt) auto sld_it = std::lower_bound(key_lookup.begin(), key_lookup.end(), key); if (sld_it == key_lookup.end() || sld_it->name != key) { + if (special_handler != nullptr && special_handler->MissingField(key, type, saveloads)) continue; // Special handler took responsibility for missing field + /* SLA_LOADCHECK triggers this debug statement a lot and is perfectly normal. */ DEBUG(sl, _sl.action == SLA_LOAD ? 2 : 6, "Field '%s' of type 0x%02X not found, skipping", key.c_str(), type); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 291630e9fb..cb344d7df8 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1071,9 +1071,15 @@ void SlObjectSaveFiltered(void *object, const SaveLoadTable &slt); void SlObjectLoadFiltered(void *object, const SaveLoadTable &slt); void SlObjectPtrOrNullFiltered(void *object, const SaveLoadTable &slt); +struct TableHeaderSpecialHandler { + virtual ~TableHeaderSpecialHandler() {} + + virtual bool MissingField(const std::string &key, uint8_t type, std::vector &saveloads) { return false; } // By default, do not handle +}; + bool SlIsTableChunk(); void SlSkipTableHeader(); -std::vector SlTableHeader(const NamedSaveLoadTable &slt); +std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); std::vector SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); void SlSaveTableObjectChunk(const SaveLoadTable &slt); void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); From e9bf53d0b13db17a082cc30eea1b43319205acf0 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 00:51:08 +0100 Subject: [PATCH 079/107] Saveload: Use table format for cheats --- src/cheat.cpp | 4 +- src/sl/cheat_sl.cpp | 154 +++++++++++++++++++++++--------------------- 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/src/cheat.cpp b/src/cheat.cpp index e22484e025..9998eb9a76 100644 --- a/src/cheat.cpp +++ b/src/cheat.cpp @@ -18,13 +18,13 @@ /** All the cheats. */ Cheats _cheats; -std::map _unknown_cheats; +std::map _unknown_cheat_fields; /** Reinitialise all the cheats. */ void InitializeCheats() { memset(&_cheats, 0, sizeof(Cheats)); - _unknown_cheats.clear(); + _unknown_cheat_fields.clear(); } /** diff --git a/src/sl/cheat_sl.cpp b/src/sl/cheat_sl.cpp index e90ca469cd..1aa78bb343 100644 --- a/src/sl/cheat_sl.cpp +++ b/src/sl/cheat_sl.cpp @@ -18,7 +18,7 @@ #include "../safeguards.h" -extern std::map _unknown_cheats; +extern std::map _unknown_cheat_fields; // This requires reference stability (during load) struct ExtraCheatNameDesc { const char *name; @@ -32,38 +32,58 @@ static ExtraCheatNameDesc _extra_cheat_descs[] = { { "town_rating", &_cheats.town_rating }, }; -static const SaveLoad _cheats_desc[] = { - SLE_VAR(Cheats, magic_bulldozer.been_used, SLE_BOOL), - SLE_VAR(Cheats, magic_bulldozer.value, SLE_BOOL), - SLE_VAR(Cheats, switch_company.been_used, SLE_BOOL), - SLE_VAR(Cheats, switch_company.value, SLE_BOOL), - SLE_VAR(Cheats, money.been_used, SLE_BOOL), - SLE_VAR(Cheats, money.value, SLE_BOOL), - SLE_VAR(Cheats, crossing_tunnels.been_used, SLE_BOOL), - SLE_VAR(Cheats, crossing_tunnels.value, SLE_BOOL), - SLE_NULL(1), - SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS(). - SLE_VAR(Cheats, no_jetcrash.been_used, SLE_BOOL), - SLE_VAR(Cheats, no_jetcrash.value, SLE_BOOL), - SLE_NULL(1), - SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS(). - SLE_VAR(Cheats, change_date.been_used, SLE_BOOL), - SLE_VAR(Cheats, change_date.value, SLE_BOOL), - SLE_VAR(Cheats, setup_prod.been_used, SLE_BOOL), - SLE_VAR(Cheats, setup_prod.value, SLE_BOOL), - SLE_NULL(1), - SLE_NULL(1), // Needs to be two NULL fields. See Load_CHTS(). - SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL), - SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL), -}; +std::vector GetCheatsDesc(bool save) { + static const NamedSaveLoad _cheats_desc[] = { + NSL("magic_bulldozer.been_used", SLE_VAR(Cheats, magic_bulldozer.been_used, SLE_BOOL)), + NSL("magic_bulldozer.value", SLE_VAR(Cheats, magic_bulldozer.value, SLE_BOOL)), + NSL("switch_company.been_used", SLE_VAR(Cheats, switch_company.been_used, SLE_BOOL)), + NSL("switch_company.value", SLE_VAR(Cheats, switch_company.value, SLE_BOOL)), + NSL("money.been_used", SLE_VAR(Cheats, money.been_used, SLE_BOOL)), + NSL("money.value", SLE_VAR(Cheats, money.value, SLE_BOOL)), + NSL("crossing_tunnels.been_used", SLE_VAR(Cheats, crossing_tunnels.been_used, SLE_BOOL)), + NSL("crossing_tunnels.value", SLE_VAR(Cheats, crossing_tunnels.value, SLE_BOOL)), + NSL("", SLE_NULL(1)), + NSL("", SLE_NULL(1)), // Needs to be two NULL fields. See Load_CHTS(). + NSL("no_jetcrash.been_used", SLE_VAR(Cheats, no_jetcrash.been_used, SLE_BOOL)), + NSL("no_jetcrash.value,", SLE_VAR(Cheats, no_jetcrash.value, SLE_BOOL)), + NSL("", SLE_NULL(1)), + NSL("", SLE_NULL(1)), // Needs to be two NULL fields. See Load_CHTS(). + NSL("change_date.been_used", SLE_VAR(Cheats, change_date.been_used, SLE_BOOL)), + NSL("change_date.value", SLE_VAR(Cheats, change_date.value, SLE_BOOL)), + NSL("setup_prod.been_used", SLE_VAR(Cheats, setup_prod.been_used, SLE_BOOL)), + NSL("setup_prod.value", SLE_VAR(Cheats, setup_prod.value, SLE_BOOL)), + NSL("", SLE_NULL(1)), + NSL("", SLE_NULL(1)), // Needs to be two NULL fields. See Load_CHTS(). + NSL("edit_max_hl.been_used", SLE_VAR(Cheats, edit_max_hl.been_used, SLE_BOOL)), + NSL("edit_max_hl.value", SLE_VAR(Cheats, edit_max_hl.value, SLE_BOOL)), + NSLT("station_rating.been_used", SLE_VAR(Cheats, station_rating.been_used, SLE_BOOL)), + NSLT("station_rating.value", SLE_VAR(Cheats, station_rating.value, SLE_BOOL)), + NSLT("inflation_cost.been_used", SLE_VAR(Cheats, inflation_cost.been_used, SLE_BOOL)), + NSLT("inflation_cost.value", SLE_VAR(Cheats, inflation_cost.value, SLE_BOOL)), + NSLT("inflation_income.been_used",SLE_VAR(Cheats, inflation_income.been_used, SLE_BOOL)), + NSLT("inflation_income.value", SLE_VAR(Cheats, inflation_income.value, SLE_BOOL)), + NSLT("town_rating.been_used", SLE_VAR(Cheats, town_rating.been_used, SLE_BOOL)), + NSLT("town_rating.value", SLE_VAR(Cheats, town_rating.value, SLE_BOOL)), + }; + + std::vector desc(std::begin(_cheats_desc), std::end(_cheats_desc)); + if (save) { + for (auto &it : _unknown_cheat_fields) { + desc.push_back(NSLT(it.first.c_str(), SLEG_VAR(it.second, SLE_BOOL))); + } + } + return desc; +} /** * Save the cheat values. */ static void Save_CHTS() { - SlSetLength(std::size(_cheats_desc)); - SlObject(&_cheats, _cheats_desc); + std::vector slt = SlTableHeader(GetCheatsDesc(true)); + + SlSetArrayIndex(0); + SlObjectSaveFiltered(&_cheats, slt); } /** @@ -71,21 +91,39 @@ static void Save_CHTS() */ static void Load_CHTS() { - size_t count = SlGetFieldLength(); - std::vector slt; + if (SlIsTableChunk()) { + struct UnknownCheatHandler : public TableHeaderSpecialHandler { + bool MissingField(const std::string &key, uint8_t type, std::vector &saveloads) override { + if (type == SLE_FILE_I8) { + DEBUG(sl, 1, "CHTS chunk: Unknown cheat field: '%s'", key.c_str()); + saveloads.push_back(SLEG_VAR(_unknown_cheat_fields[key], SLE_BOOL)); + return true; + } - /* Cheats were added over the years without a savegame bump. They are - * stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs - * are stored for this savegame. So read only "count" SLE_BOOLs (and in - * result "count / 2" cheats). */ - for (auto &sld : _cheats_desc) { - count--; - slt.push_back(sld); + return false; + } + }; - if (count == 0) break; + UnknownCheatHandler uch{}; + std::vector slt = SlTableHeader(GetCheatsDesc(false), &uch); + + if (SlIterateArray() == -1) return; + SlObjectLoadFiltered(&_cheats, slt); + if (SlIterateArray() != -1) { + SlErrorCorruptFmt("Too many CHTS entries"); + } + } else { + size_t count = SlGetFieldLength(); + std::vector slt = SlTableHeaderOrRiff(GetCheatsDesc(false)); + + /* Cheats were added over the years without a savegame bump. They are + * stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs + * are stored for this savegame. So read only "count" SLE_BOOLs (and in + * result "count / 2" cheats). */ + if (count < slt.size()) slt.resize(count); + + SlObject(&_cheats, slt); } - - SlObject(&_cheats, slt); } /** @@ -125,46 +163,16 @@ static void Load_CHTX() } if (!found) { DEBUG(sl, 1, "CHTX chunk: Could not find cheat: '%s'", current_cheat.name); - _unknown_cheats[current_cheat.name] = current_cheat.cht; + _unknown_cheat_fields[std::string(current_cheat.name) + ".been_used"] = current_cheat.cht.been_used; + _unknown_cheat_fields[std::string(current_cheat.name) + ".value"] = current_cheat.cht.value; } } } -/** - * Save the extra cheat values. - */ -static void Save_CHTX() -{ - struct CheatsExtSave { - const char *name; - Cheat cht; - }; - - static const SaveLoad _cheats_ext_save_desc[] = { - SLE_STR(CheatsExtSave, name, SLE_STR, 0), - SLE_VAR(CheatsExtSave, cht.been_used, SLE_BOOL), - SLE_VAR(CheatsExtSave, cht.value, SLE_BOOL), - }; - - SlAutolength([](void *) { - SlWriteUint32(0); // flags - SlWriteUint32((uint32_t)(lengthof(_extra_cheat_descs) + _unknown_cheats.size())); // cheat count - - for (uint j = 0; j < lengthof(_extra_cheat_descs); j++) { - CheatsExtSave save = { _extra_cheat_descs[j].name, *(_extra_cheat_descs[j].cht) }; - SlObject(&save, _cheats_ext_save_desc); - } - for (const auto &iter : _unknown_cheats) { - CheatsExtSave save = { iter.first.c_str(), iter.second }; - SlObject(&save, _cheats_ext_save_desc); - } - }, nullptr); -} - /** Chunk handlers related to cheats. */ static const ChunkHandler cheat_chunk_handlers[] = { - { 'CHTS', Save_CHTS, Load_CHTS, nullptr, nullptr, CH_RIFF }, - { 'CHTX', Save_CHTX, Load_CHTX, nullptr, nullptr, CH_RIFF }, + { 'CHTS', Save_CHTS, Load_CHTS, nullptr, nullptr, CH_TABLE }, + { 'CHTX', nullptr, Load_CHTX, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _cheat_chunk_handlers(cheat_chunk_handlers); From e57a7ad2733b74336a3869d0a421841a7046e8ac Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 11:24:58 +0100 Subject: [PATCH 080/107] Saveload: Bump savegame version for cheats --- src/sl/extended_ver_sl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 819b97c82f..c6f4568ec4 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -143,7 +143,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_SPEED_RESTRICTION, XSCF_NULL, 1, 1, "speed_restriction", nullptr, nullptr, "VESR" }, { XSLFI_STATION_GOODS_EXTRA, XSCF_NULL, 1, 1, "station_goods_extra", nullptr, nullptr, nullptr }, { XSLFI_DOCKING_CACHE_VER, XSCF_IGNORABLE_ALL, 3, 3, "docking_cache_ver", nullptr, nullptr, nullptr }, - { XSLFI_EXTRA_CHEATS, XSCF_NULL, 1, 1, "extra_cheats", nullptr, nullptr, "CHTX" }, + { XSLFI_EXTRA_CHEATS, XSCF_NULL, 2, 2, "extra_cheats", nullptr, nullptr, nullptr }, { XSLFI_TOWN_MULTI_BUILDING, XSCF_NULL, 1, 1, "town_multi_building", nullptr, nullptr, nullptr }, { XSLFI_SHIP_LOST_COUNTER, XSCF_NULL, 1, 1, "ship_lost_counter", nullptr, nullptr, nullptr }, { XSLFI_BUILD_OBJECT_RATE_LIMIT, XSCF_NULL, 1, 1, "build_object_rate_limit", nullptr, nullptr, nullptr }, From acfe8909b42ee7ba44f1782c322a0bebce209831 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 11:53:18 +0100 Subject: [PATCH 081/107] Saveload: Add NamedSaveLoad to saveload_common.h --- src/sl/saveload_common.h | 2 ++ src/sl/saveload_types.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sl/saveload_common.h b/src/sl/saveload_common.h index 8647f47514..f7a51a83de 100644 --- a/src/sl/saveload_common.h +++ b/src/sl/saveload_common.h @@ -13,9 +13,11 @@ #include "../strings_type.h" struct SaveLoad; +struct NamedSaveLoad; /** A table of SaveLoad entries. */ using SaveLoadTable = std::span; +using NamedSaveLoadTable = std::span; namespace upstream_sl { struct SaveLoad; diff --git a/src/sl/saveload_types.h b/src/sl/saveload_types.h index 835c9ba286..afeb1501f3 100644 --- a/src/sl/saveload_types.h +++ b/src/sl/saveload_types.h @@ -162,6 +162,5 @@ inline constexpr NamedSaveLoad NSLT(const char *name, SaveLoad save_load) { return { name, save_load, NSLF_TABLE_ONLY }; } -using NamedSaveLoadTable = std::span; #endif /* SL_SAVELOAD_TYPES_H */ From f739710ad34f43a10fa1c65359935fe4145634ad Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Jul 2024 12:03:58 +0100 Subject: [PATCH 082/107] Saveload: Use table format for CAPA chunk --- src/cargopacket.h | 4 ++-- src/sl/cargopacket_sl.cpp | 40 ++++++++++++++++++++------------------ src/sl/extended_ver_sl.cpp | 2 +- src/sl/extended_ver_sl.h | 1 + 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/cargopacket.h b/src/cargopacket.h index 317c889aa5..e1604fcd12 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -35,7 +35,7 @@ struct GoodsEntry; // forward-declare for Stage() and RerouteStalePackets() template class CargoList; class StationCargoList; // forward-declare, so we can use it in VehicleCargoList. -extern SaveLoadTable GetCargoPacketDesc(); +extern NamedSaveLoadTable GetCargoPacketDesc(); namespace upstream_sl { extern upstream_sl::SaveLoadTable GetCargoPacketDesc(); @@ -79,7 +79,7 @@ private: friend class VehicleCargoList; friend class StationCargoList; /** We want this to be saved, right? */ - friend SaveLoadTable GetCargoPacketDesc(); + friend NamedSaveLoadTable GetCargoPacketDesc(); friend upstream_sl::SaveLoadTable upstream_sl::GetCargoPacketDesc(); friend void Load_CPDP(); public: diff --git a/src/sl/cargopacket_sl.cpp b/src/sl/cargopacket_sl.cpp index 40d3edb90a..542ba1e897 100644 --- a/src/sl/cargopacket_sl.cpp +++ b/src/sl/cargopacket_sl.cpp @@ -155,23 +155,23 @@ extern btree::btree_map _cargo_packet_deferred_payments; * some of the variables itself are private. * @return the saveload description for CargoPackets. */ -SaveLoadTable GetCargoPacketDesc() +NamedSaveLoadTable GetCargoPacketDesc() { - static const SaveLoad _cargopacket_desc[] = { - SLE_VAR(CargoPacket, first_station, SLE_UINT16), - SLE_VAR(CargoPacket, source_xy, SLE_UINT32), - SLE_VAR(CargoPacket, next_hop, SLE_FILE_U32 | SLE_VAR_U16), - SLE_VAR(CargoPacket, count, SLE_UINT16), - SLE_CONDVAR_X(CargoPacket, periods_in_transit, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE, 0, 0)), - SLE_CONDVAR_X(CargoPacket, periods_in_transit, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE)), - SLE_VAR(CargoPacket, feeder_share, SLE_INT64), - SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION), - SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION), - SLE_CONDVAR_X(CargoPacket, travelled.x, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TRAVELLED)), - SLE_CONDVAR_X(CargoPacket, travelled.y, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TRAVELLED)), + static const NamedSaveLoad _cargopacket_desc[] = { + NSL("source", SLE_VAR(CargoPacket, first_station, SLE_UINT16)), + NSL("source_xy", SLE_VAR(CargoPacket, source_xy, SLE_UINT32)), + NSL("loaded_at_xy", SLE_VAR(CargoPacket, next_hop, SLE_FILE_U32 | SLE_VAR_U16)), + NSL("count", SLE_VAR(CargoPacket, count, SLE_UINT16)), + NSL("periods_in_transit", SLE_CONDVAR_X(CargoPacket, periods_in_transit, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE, 0, 0))), + NSL("periods_in_transit", SLE_CONDVAR_X(CargoPacket, periods_in_transit, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_CARGO_AGE))), + NSL("feeder_share", SLE_VAR(CargoPacket, feeder_share, SLE_INT64)), + NSL("source_type", SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, SLV_125, SL_MAX_VERSION)), + NSL("source_id", SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, SLV_125, SL_MAX_VERSION)), + NSL("travelled.x", SLE_CONDVAR_X(CargoPacket, travelled.x, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TRAVELLED))), + NSL("travelled.y", SLE_CONDVAR_X(CargoPacket, travelled.y, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TRAVELLED))), /* Used to be paid_for, but that got changed. */ - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_121), + NSL("", SLE_CONDNULL(1, SL_MIN_VERSION, SLV_121)), }; return _cargopacket_desc; } @@ -181,10 +181,11 @@ SaveLoadTable GetCargoPacketDesc() */ static void Save_CAPA() { - std::vector filtered_packet_desc = SlFilterObject(GetCargoPacketDesc()); + std::vector slt = SlTableHeader(GetCargoPacketDesc()); + for (CargoPacket *cp : CargoPacket::Iterate()) { SlSetArrayIndex(cp->index); - SlObjectSaveFiltered(cp, filtered_packet_desc); + SlObjectSaveFiltered(cp, slt); } } @@ -193,11 +194,12 @@ static void Save_CAPA() */ static void Load_CAPA() { - std::vector filtered_packet_desc = SlFilterObject(GetCargoPacketDesc()); + std::vector slt = SlTableHeaderOrRiff(GetCargoPacketDesc()); + int index; while ((index = SlIterateArray()) != -1) { CargoPacket *cp = new (index) CargoPacket(); - SlObjectLoadFiltered(cp, filtered_packet_desc); + SlObjectLoadFiltered(cp, slt); } } @@ -237,7 +239,7 @@ void Load_CPDP() /** Chunk handlers related to cargo packets. */ static const ChunkHandler cargopacket_chunk_handlers[] = { - { 'CAPA', Save_CAPA, Load_CAPA, nullptr, nullptr, CH_ARRAY }, + { 'CAPA', Save_CAPA, Load_CAPA, nullptr, nullptr, CH_TABLE }, { 'CPDP', Save_CPDP, Load_CPDP, nullptr, nullptr, CH_RIFF }, }; diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index c6f4568ec4..d38a72f663 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -214,7 +214,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_VEHICLE_ECONOMY_AGE, XSCF_NULL, 1, 1, "slv_vehicle_economy_age", nullptr, nullptr, nullptr }, { XSLFI_TABLE_PATS, XSCF_NULL, 1, 1, "table_pats", nullptr, nullptr, nullptr }, - { XSLFI_TABLE_MISC_SL, XSCF_NULL, 2, 2, "table_misc_sl", nullptr, nullptr, nullptr }, + { XSLFI_TABLE_MISC_SL, XSCF_NULL, 3, 3, "table_misc_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_SCRIPT_SL, XSCF_NULL, 1, 1, "table_script_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_NEWGRF_SL, XSCF_NULL, 2, 2, "table_newgrf_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_INDUSTRY_SL, XSCF_NULL, 1, 1, "table_industry_sl", nullptr, nullptr, nullptr }, diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index ce2e7b7be7..346d480560 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -166,6 +166,7 @@ enum SlXvFeatureIndex { XSLFI_TABLE_MISC_SL, ///< Use upstream table format for miscellaneous chunks: ///< v1: DATE, VIEW, MAPS ///< v2: SUBS, CMDL, CMPU, ERNW, DEPT, CAPY, ECMY, EIDS, ENGN, GOAL, GRPS, RAIL, OBJS, SIGN, PSAC, STPE, STPA + ///< v3: CAPA XSLFI_TABLE_SCRIPT_SL, ///< Use upstream table format for script chunks XSLFI_TABLE_NEWGRF_SL, ///< Use upstream table format for NewGRF/ID mapping chunks ///< In v1, NGRF chunks were saved incorrectly: see SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING From 159e68c4dc61f4e408f9d0b7116b5e1da542a739 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 00:08:42 +0100 Subject: [PATCH 083/107] Saveload: Remove intermediate copy in map individual chunk save/load --- src/sl/map_sl.cpp | 176 +++++++++++++++------------------------ src/sl/saveload_buffer.h | 55 ++++++++++++ 2 files changed, 123 insertions(+), 108 deletions(-) diff --git a/src/sl/map_sl.cpp b/src/sl/map_sl.cpp index c0c9cf28c0..9f62cfd1f0 100644 --- a/src/sl/map_sl.cpp +++ b/src/sl/map_sl.cpp @@ -54,17 +54,12 @@ static void Check_MAPS() _load_check_data.map_size_y = _map_dim_y; } -static const uint MAP_SL_BUF_SIZE = 4096; - static void Load_MAPT() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].type = val; + }); } static void Check_MAPH_common() @@ -88,128 +83,101 @@ static void Load_MAPH() if (SlXvIsFeaturePresent(XSLFI_CHILLPP)) { if (SlGetFieldLength() != 0) { _sl_xv_feature_versions[XSLFI_HEIGHT_8_BIT] = 2; - std::array buf; - TileIndex size = MapSize(); - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadUint16sToHandler(MapSize(), [&](uint16_t val) { + _m[i++].height = val; + }); } return; } - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].height = val; + }); } static void Load_MAP1() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].m1 = val; + }); } static void Load_MAP2() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, - /* In those versions the m2 was 8 bits */ - IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 - ); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; + TileIndex i = 0; + if (IsSavegameVersionBefore(SLV_5)) { + /* In those versions the m2 was 8 bits */ + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].m2 = val; + }); + } else { + ReadBuffer::GetCurrent()->ReadUint16sToHandler(MapSize(), [&](uint16_t val) { + _m[i++].m2 = val; + }); } } static void Load_MAP3() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].m3 = val; + }); } static void Load_MAP4() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].m4 = val; + }); } static void Load_MAP5() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _m[i++].m5 = val; + }); } static void Load_MAP6() { - std::array buf; TileIndex size = MapSize(); + TileIndex i = 0; if (IsSavegameVersionBefore(SLV_42)) { - for (TileIndex i = 0; i != size;) { - /* 1024, otherwise we overflow on 64x64 maps! */ - SlArray(buf.data(), 1024, SLE_UINT8); - for (uint j = 0; j != 1024; j++) { - _me[i++].m6 = GB(buf[j], 0, 2); - _me[i++].m6 = GB(buf[j], 2, 2); - _me[i++].m6 = GB(buf[j], 4, 2); - _me[i++].m6 = GB(buf[j], 6, 2); - } - } + ReadBuffer::GetCurrent()->ReadBytesToHandler(size / 4, [&](uint8_t val) { + _me[i++].m6 = GB(val, 0, 2); + _me[i++].m6 = GB(val, 2, 2); + _me[i++].m6 = GB(val, 4, 2); + _me[i++].m6 = GB(val, 6, 2); + }); } else { - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j]; - } + ReadBuffer::GetCurrent()->ReadBytesToHandler(size, [&](uint8_t val) { + _me[i++].m6 = val; + }); } } static void Load_MAP7() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadBytesToHandler(MapSize(), [&](uint8_t val) { + _me[i++].m7 = val; + }); } static void Load_MAP8() { - std::array buf; - TileIndex size = MapSize(); - - for (TileIndex i = 0; i != size;) { - SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j]; - } + TileIndex i = 0; + ReadBuffer::GetCurrent()->ReadUint16sToHandler(MapSize(), [&](uint16_t val) { + _me[i++].m8 = val; + }); } static void Load_WMAP() @@ -347,33 +315,25 @@ struct MAP8 { static const FieldT &GetField(TileIndex t) { return _me[t].m8; } }; -template -struct MAP_VarType {}; - -template <> -struct MAP_VarType -{ - static const VarType var_type = SLE_UINT8; -}; - -template <> -struct MAP_VarType -{ - static const VarType var_type = SLE_UINT16; -}; - template static void Save_MAP() { assert(_sl_xv_feature_versions[XSLFI_WHOLE_MAP_CHUNK] == 0); - std::array buf; - TileIndex size = MapSize(); + static_assert(std::is_same_v || std::is_same_v); + TileIndex size = MapSize(); SlSetLength(size * sizeof(typename T::FieldT)); - for (TileIndex i = 0; i != size;) { - for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = T::GetField(i++); - SlArray(buf.data(), MAP_SL_BUF_SIZE, MAP_VarType::var_type); + + TileIndex i = 0; + if constexpr (std::is_same_v) { + MemoryDumper::GetCurrent()->WriteBytesFromHandler(size, [&]() -> uint8_t { + return T::GetField(i++); + }); + } else { + MemoryDumper::GetCurrent()->WriteUint16sFromHandler(size, [&]() -> uint16_t { + return T::GetField(i++); + }); } } diff --git a/src/sl/saveload_buffer.h b/src/sl/saveload_buffer.h index 1e18790f30..c45eb6ae67 100644 --- a/src/sl/saveload_buffer.h +++ b/src/sl/saveload_buffer.h @@ -139,6 +139,34 @@ struct ReadBuffer { this->CopyBytes(buffer.data(), buffer.size()); } + template + inline void ReadBytesToHandler(size_t length, F handler) + { + while (length) { + if (unlikely(this->bufp == this->bufe)) { + this->AcquireBytes(); + } + size_t to_copy = std::min(this->bufe - this->bufp, length); + for (size_t i = 0; i < to_copy; i++) { + handler(this->RawReadByte()); + } + length -= to_copy; + } + } + + template + inline void ReadUint16sToHandler(size_t length, F handler) + { + while (length) { + this->CheckBytes(2); + size_t to_copy = std::min((this->bufe - this->bufp) / 2, length); + for (size_t i = 0; i < to_copy; i++) { + handler(this->RawReadUint16()); + } + length -= to_copy; + } + } + /** * Get the size of the memory dump made so far. * @return The size. @@ -274,6 +302,33 @@ struct MemoryDumper { this->buf += 8; } + template + inline void WriteBytesFromHandler(size_t length, F handler) + { + while (length) { + this->CheckBytes(1); + size_t to_copy = std::min(this->bufe - this->buf, length); + for (size_t i = 0; i < to_copy; i++) { + this->RawWriteByte(handler()); + } + length -= to_copy; + } + } + + template + inline void WriteUint16sFromHandler(size_t length, F handler) + { + while (length) { + this->CheckBytes(2); + size_t to_copy = std::min((this->bufe - this->buf) / 2, length); + for (size_t i = 0; i < to_copy; i++) { + this->RawWriteUint16(handler()); + } + length -= to_copy; + } + } + + void Flush(SaveFilter &writer); size_t GetSize() const; void StartAutoLength(); From 7ddcf901f563110872646fcddce18c939a8a2a02 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 12:11:49 +0100 Subject: [PATCH 084/107] Saveload: Add a label tag field to SaveLoad --- src/sl/saveload.cpp | 2 +- src/sl/saveload.h | 11 +++++------ src/sl/saveload_types.h | 13 +++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 7f85345a47..5f26856071 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2277,7 +2277,7 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp } /* We don't know this field, so read to nothing. */ - saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, SlXvFeatureTest() }); + saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_TABLE_UNKNOWN, nullptr, 0, SlXvFeatureTest() }); continue; } diff --git a/src/sl/saveload.h b/src/sl/saveload.h index cb344d7df8..ce842a2043 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -501,7 +501,7 @@ inline constexpr void *SlVarWrapper(void* ptr) * @param extver SlXvFeatureTest to test (along with from and to) which savegames have the field * @note In general, it is better to use one of the SLE_* macros below. */ -#define SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extver) SaveLoad {false, cmd, type, length, from, to, SlVarWrapper((void*)cpp_offsetof(base, variable)), sizeof(base::variable), extver} +#define SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extver) SaveLoad {false, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)cpp_offsetof(base, variable)), sizeof(base::variable), extver} #define SLE_GENERAL(cmd, base, variable, type, length, from, to) SLE_GENERAL_X(cmd, base, variable, type, length, from, to, SlXvFeatureTest()) /** @@ -719,8 +719,8 @@ inline constexpr void *SlVarWrapper(void* ptr) /** Translate values ingame to different values in the savegame and vv. */ #define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION) -#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, SlXvFeatureTest()} -#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, SlXvFeatureTest()} +#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, 0, SlXvFeatureTest()} +#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, 0, SlXvFeatureTest()} /** * Storage of global simple variables, references (pointers), and arrays. @@ -732,7 +732,7 @@ inline constexpr void *SlVarWrapper(void* ptr) * @param extver SlXvFeatureTest to test (along with from and to) which savegames have the field * @note In general, it is better to use one of the SLEG_* macros below. */ -#define SLEG_GENERAL_X(cmd, variable, type, length, from, to, extver) SaveLoad {true, cmd, type, length, from, to, SlVarWrapper((void*)&variable), sizeof(variable), extver} +#define SLEG_GENERAL_X(cmd, variable, type, length, from, to, extver) SaveLoad {true, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)&variable), sizeof(variable), extver} #define SLEG_GENERAL(cmd, variable, type, length, from, to) SLEG_GENERAL_X(cmd, variable, type, length, from, to, SlXvFeatureTest()) /** @@ -896,9 +896,8 @@ inline constexpr void *SlVarWrapper(void* ptr) * @param length Length of the empty space. * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. - * @param extver SlXvFeatureTest to test (along with from and to) which savegames have empty space */ -#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, (void*)nullptr, SlXvFeatureTest()} +#define SLEG_CONDNULL(length, from, to) SaveLoad {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL, length, from, to, SLTAG_DEFAULT, nullptr, SlXvFeatureTest()} /** * Checks whether the savegame is below \a major.\a minor. diff --git a/src/sl/saveload_types.h b/src/sl/saveload_types.h index afeb1501f3..0928cfc781 100644 --- a/src/sl/saveload_types.h +++ b/src/sl/saveload_types.h @@ -131,6 +131,7 @@ struct SaveLoad { uint16_t length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements) SaveLoadVersion version_from; ///< save/load the variable starting from this savegame version SaveLoadVersion version_to; ///< save/load the variable until this savegame version + uint16_t label_tag; ///< for labelling purposes /* NOTE: This element either denotes the address of the variable for a global * variable, or the offset within a struct which is then bound to a variable * during runtime. Decision on which one to use is controlled by the function @@ -140,6 +141,18 @@ struct SaveLoad { SlXvFeatureTest ext_feature_test; ///< extended feature test }; +inline constexpr SaveLoad SLTAG(uint16_t label_tag, SaveLoad save_load) +{ + save_load.label_tag = label_tag; + return save_load; +} + +enum SaveLoadTags { + SLTAG_DEFAULT, + SLTAG_TABLE_UNKNOWN, + SLTAG_CUSTOM_START, +}; + enum NamedSaveLoadFlags : uint8_t { NSLF_NONE = 0, NSLF_TABLE_ONLY = 1 << 0, From 74047028dd942141c58ac98e0ee598795ffeedcf Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 18:00:47 +0100 Subject: [PATCH 085/107] Saveload: Remove unused size field from struct SaveLoad --- src/saveload/saveload.cpp | 4 ++-- src/saveload/saveload.h | 9 ++++----- src/saveload/settings_sl.cpp | 4 ++-- src/sl/saveload.cpp | 2 +- src/sl/saveload.h | 8 ++++---- src/sl/saveload_types.h | 1 - 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2b5bd2168b..fabbbaba3c 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1680,7 +1680,7 @@ std::vector SlTableHeader(const SaveLoadTable &slt) } /* We don't know this field, so read to nothing. */ - saveloads.push_back({key, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, handler}); + saveloads.push_back({key, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, handler}); continue; } @@ -1787,7 +1787,7 @@ std::vector SlCompatTableHeader(const SaveLoadTable &slt, const SaveLo /* In old savegames there can be data we no longer care for. We * skip this by simply reading the amount of bytes indicated and * send those to /dev/null. */ - saveloads.push_back({"", SL_NULL, GetVarFileType(slc.null_type) | SLE_VAR_NULL, slc.null_length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr}); + saveloads.push_back({"", SL_NULL, GetVarFileType(slc.null_type) | SLE_VAR_NULL, slc.null_length, slc.version_from, slc.version_to, nullptr, 0, nullptr}); } else { auto sld_it = key_lookup.find(slc.name); /* If this branch triggers, it means that an entry in the diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 50abc9804f..c4aabf6266 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -296,7 +296,6 @@ struct SaveLoad { uint16_t length; ///< (Conditional) length of the variable (eg. arrays) (max array size is 65536 elements). SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version. SaveLoadVersion version_to; ///< Save/load the variable before this savegame version. - size_t size; ///< The sizeof size. SaveLoadAddrProc *address_proc; ///< Callback proc the get the actual variable address in memory. size_t extra_data; ///< Extra data for the callback proc. std::shared_ptr handler; ///< Custom handler for Save/Load procs. @@ -415,7 +414,7 @@ inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t leng * @note In general, it is better to use one of the SLE_* macros below. */ #define SLE_GENERAL_NAME(cmd, name, base, variable, type, length, from, to, extra) \ - SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { \ + SaveLoad {name, cmd, type, length, from, to, [] (void *b, size_t) -> void * { \ static_assert(SlCheckVarSize(cmd, type, length, sizeof(static_cast(b)->variable))); \ assert(b != nullptr); \ return const_cast(static_cast(std::addressof(static_cast(b)->variable))); \ @@ -638,7 +637,7 @@ inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t leng * @note In general, it is better to use one of the SLEG_* macros below. */ #define SLEG_GENERAL(name, cmd, variable, type, length, from, to, extra) \ - SaveLoad {name, cmd, type, length, from, to, sizeof(variable), [] (void *, size_t) -> void * { \ + SaveLoad {name, cmd, type, length, from, to, [] (void *, size_t) -> void * { \ static_assert(SlCheckVarSize(cmd, type, length, sizeof(variable))); \ return static_cast(std::addressof(variable)); }, extra, nullptr} @@ -701,7 +700,7 @@ inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t leng * @param from First savegame version that has the struct. * @param to Last savegame version that has the struct. */ -#define SLEG_CONDSTRUCT(name, handler, from, to) SaveLoad {name, SL_STRUCT, 0, 0, from, to, 0, nullptr, 0, std::make_shared()} +#define SLEG_CONDSTRUCT(name, handler, from, to) SaveLoad {name, SL_STRUCT, 0, 0, from, to, nullptr, 0, std::make_shared()} /** * Storage of a global reference list in some savegame versions. @@ -750,7 +749,7 @@ inline constexpr bool SlCheckVarSize(SaveLoadType cmd, VarType type, size_t leng * @param from First savegame version that has the list. * @param to Last savegame version that has the list. */ -#define SLEG_CONDSTRUCTLIST(name, handler, from, to) SaveLoad {name, SL_STRUCTLIST, 0, 0, from, to, 0, nullptr, 0, std::make_shared()} +#define SLEG_CONDSTRUCTLIST(name, handler, from, to) SaveLoad {name, SL_STRUCTLIST, 0, 0, from, to, nullptr, 0, std::make_shared()} /** * Storage of a global variable in every savegame version. diff --git a/src/saveload/settings_sl.cpp b/src/saveload/settings_sl.cpp index af2527e9ac..e8b237db46 100644 --- a/src/saveload/settings_sl.cpp +++ b/src/saveload/settings_sl.cpp @@ -139,7 +139,7 @@ static std::vector GetSettingsDesc(bool is_loading) if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { /* We don't want to read this setting, so we do need to skip over it. */ - saveloads.push_back({sd->name, new_cmd, GetVarFileType(new_type) | SLE_VAR_NULL, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, nullptr}); + saveloads.push_back({sd->name, new_cmd, GetVarFileType(new_type) | SLE_VAR_NULL, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, nullptr}); } continue; } @@ -147,7 +147,7 @@ static std::vector GetSettingsDesc(bool is_loading) SaveLoadAddrProc *address_proc = [](void *base, size_t extra) -> void* { return const_cast((const uint8_t *)base + (ptrdiff_t)extra); }; - saveloads.push_back({sd->name, new_cmd, new_type, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, sd->save.size, address_proc, reinterpret_cast(sd->save.address), nullptr}); + saveloads.push_back({sd->name, new_cmd, new_type, sd->save.length, SL_MIN_VERSION, SL_MAX_VERSION, address_proc, reinterpret_cast(sd->save.address), nullptr}); } return saveloads; diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 5f26856071..d96f92e8f1 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2277,7 +2277,7 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp } /* We don't know this field, so read to nothing. */ - saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_TABLE_UNKNOWN, nullptr, 0, SlXvFeatureTest() }); + saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_TABLE_UNKNOWN, nullptr, SlXvFeatureTest() }); continue; } diff --git a/src/sl/saveload.h b/src/sl/saveload.h index ce842a2043..b63d685fdf 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -501,7 +501,7 @@ inline constexpr void *SlVarWrapper(void* ptr) * @param extver SlXvFeatureTest to test (along with from and to) which savegames have the field * @note In general, it is better to use one of the SLE_* macros below. */ -#define SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extver) SaveLoad {false, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)cpp_offsetof(base, variable)), sizeof(base::variable), extver} +#define SLE_GENERAL_X(cmd, base, variable, type, length, from, to, extver) SaveLoad {false, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)cpp_offsetof(base, variable)), extver} #define SLE_GENERAL(cmd, base, variable, type, length, from, to) SLE_GENERAL_X(cmd, base, variable, type, length, from, to, SlXvFeatureTest()) /** @@ -719,8 +719,8 @@ inline constexpr void *SlVarWrapper(void* ptr) /** Translate values ingame to different values in the savegame and vv. */ #define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION) -#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, 0, SlXvFeatureTest()} -#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, 0, SlXvFeatureTest()} +#define SLE_VEH_INCLUDE() SaveLoad { false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, SlXvFeatureTest()} +#define SLE_ST_INCLUDE() SaveLoad { false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_DEFAULT, nullptr, SlXvFeatureTest()} /** * Storage of global simple variables, references (pointers), and arrays. @@ -732,7 +732,7 @@ inline constexpr void *SlVarWrapper(void* ptr) * @param extver SlXvFeatureTest to test (along with from and to) which savegames have the field * @note In general, it is better to use one of the SLEG_* macros below. */ -#define SLEG_GENERAL_X(cmd, variable, type, length, from, to, extver) SaveLoad {true, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)&variable), sizeof(variable), extver} +#define SLEG_GENERAL_X(cmd, variable, type, length, from, to, extver) SaveLoad {true, cmd, type, length, from, to, SLTAG_DEFAULT, SlVarWrapper((void*)&variable), extver} #define SLEG_GENERAL(cmd, variable, type, length, from, to) SLEG_GENERAL_X(cmd, variable, type, length, from, to, SlXvFeatureTest()) /** diff --git a/src/sl/saveload_types.h b/src/sl/saveload_types.h index 0928cfc781..3235dc3818 100644 --- a/src/sl/saveload_types.h +++ b/src/sl/saveload_types.h @@ -137,7 +137,6 @@ struct SaveLoad { * during runtime. Decision on which one to use is controlled by the function * that is called to save it. address: global=true, offset: global=false */ void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) - size_t size; ///< the sizeof size. SlXvFeatureTest ext_feature_test; ///< extended feature test }; From 99c6cc5bdbfdf5a686a10dc20e23c1b78762c5f5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 18:45:17 +0100 Subject: [PATCH 086/107] Saveload: Use template function to implement SlAutolength --- src/sl/company_sl.cpp | 2 +- src/sl/linkgraph_sl.cpp | 4 ++-- src/sl/order_sl.cpp | 10 ++++------ src/sl/plans_sl.cpp | 2 +- src/sl/saveload.cpp | 12 +++++------- src/sl/saveload.h | 18 ++++++++++++++++-- src/sl/station_sl.cpp | 2 +- src/sl/town_sl.cpp | 2 +- src/sl/vehicle_sl.cpp | 6 +++--- 9 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index 8360a94508..34023f5ec8 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -491,7 +491,7 @@ static void Save_PLYR() { for (Company *c : Company::Iterate()) { SlSetArrayIndex(c->index); - SlAutolength((AutolengthProc*)SaveLoad_PLYR, c); + SlAutolength(SaveLoad_PLYR, c); } } diff --git a/src/sl/linkgraph_sl.cpp b/src/sl/linkgraph_sl.cpp index ce5830b6e7..ac781c4a7b 100644 --- a/src/sl/linkgraph_sl.cpp +++ b/src/sl/linkgraph_sl.cpp @@ -336,7 +336,7 @@ static void Save_LGRP() FilterDescs(); for (LinkGraph *lg : LinkGraph::Iterate()) { SlSetArrayIndex(lg->index); - SlAutolength((AutolengthProc*)DoSave_LGRP, lg); + SlAutolength(DoSave_LGRP, lg); } } @@ -348,7 +348,7 @@ static void Save_LGRJ() FilterDescs(); for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { SlSetArrayIndex(lgj->index); - SlAutolength((AutolengthProc*)DoSave_LGRJ, lgj); + SlAutolength(DoSave_LGRJ, lgj); } } diff --git a/src/sl/order_sl.cpp b/src/sl/order_sl.cpp index f1ad9a8230..7c2af243d0 100644 --- a/src/sl/order_sl.cpp +++ b/src/sl/order_sl.cpp @@ -364,14 +364,13 @@ static void Save_ORDL() SetupDescs_ORDL(); for (OrderList *list : OrderList::Iterate()) { SlSetArrayIndex(list->index); - SlAutolength([](void *data) { - OrderList *list = static_cast(data); + SlAutolength([&]() { SlObjectSaveFiltered(list, _filtered_ordl_desc); SlWriteUint32(list->GetScheduledDispatchScheduleCount()); for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { SaveDispatchSchedule(ds); } - }, list); + }); } } @@ -458,14 +457,13 @@ void Save_BKOR() for (OrderBackup *ob : OrderBackup::Iterate()) { SlSetArrayIndex(ob->index); - SlAutolength([](void *data) { - OrderBackup *ob = static_cast(data); + SlAutolength([&]() { SlObject(ob, GetOrderBackupDescription()); SlWriteUint32((uint)ob->dispatch_schedules.size()); for (DispatchSchedule &ds : ob->dispatch_schedules) { SaveDispatchSchedule(ds); } - }, ob); + }); } } diff --git a/src/sl/plans_sl.cpp b/src/sl/plans_sl.cpp index 89e83dd07e..f3544b4839 100644 --- a/src/sl/plans_sl.cpp +++ b/src/sl/plans_sl.cpp @@ -40,7 +40,7 @@ static void Save_PLAN() { for (Plan *p : Plan::Iterate()) { SlSetArrayIndex(p->index); - SlAutolength((AutolengthProc*) RealSave_PLAN, p); + SlAutolength(RealSave_PLAN, p); } } diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index d96f92e8f1..1ad1459931 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2383,19 +2383,17 @@ void SlGlobList(const SaveLoadTable &slt) SlObject(nullptr, slt); } -/** - * Do something of which I have no idea what it is :P - * @param proc The callback procedure that is called - * @param arg The variable that will be used for the callback procedure - */ -void SlAutolength(AutolengthProc *proc, void *arg) +void SlAutolengthSetup() { assert(_sl.action == SLA_SAVE); assert(_sl.need_length == NL_WANTLENGTH); _sl.need_length = NL_NONE; _sl.dumper->StartAutoLength(); - proc(arg); +} + +void SlAutolengthCompletion() +{ auto result = _sl.dumper->StopAutoLength(); /* Setup length */ _sl.need_length = NL_WANTLENGTH; diff --git a/src/sl/saveload.h b/src/sl/saveload.h index b63d685fdf..18c3ae9097 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -83,7 +83,6 @@ bool IsNetworkServerSave(); bool IsScenarioSave(); typedef void ChunkSaveLoadProc(); -typedef void AutolengthProc(void *arg); void SlUnreachablePlaceholder(); @@ -980,12 +979,27 @@ void WriteValue(void *ptr, VarType conv, int64_t val); void SlSetArrayIndex(uint index); int SlIterateArray(); -void SlAutolength(AutolengthProc *proc, void *arg); size_t SlGetFieldLength(); void SlSetLength(size_t length); size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld); size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt); +/** + * Run proc, automatically prepending the written length + * @param proc The callback procedure that is called + * @param args Any + */ +template +void SlAutolength(F proc, Args... args) +{ + extern void SlAutolengthSetup(); + extern void SlAutolengthCompletion(); + + SlAutolengthSetup(); + proc(std::forward(args)...); + SlAutolengthCompletion(); +} + /** * Run proc, saving result in the autolength temp buffer * @param proc The callback procedure that is called diff --git a/src/sl/station_sl.cpp b/src/sl/station_sl.cpp index 7acb434382..1555acdb6e 100644 --- a/src/sl/station_sl.cpp +++ b/src/sl/station_sl.cpp @@ -622,7 +622,7 @@ static void Save_STNN() /* Write the stations */ for (BaseStation *st : BaseStation::Iterate()) { SlSetArrayIndex(st->index); - SlAutolength((AutolengthProc*)RealSave_STNN, st); + SlAutolength(RealSave_STNN, st); } } diff --git a/src/sl/town_sl.cpp b/src/sl/town_sl.cpp index 754cbda0e7..008b4acd3f 100644 --- a/src/sl/town_sl.cpp +++ b/src/sl/town_sl.cpp @@ -317,7 +317,7 @@ static void Save_TOWN() SetupDescs_TOWN(); for (Town *t : Town::Iterate()) { SlSetArrayIndex(t->index); - SlAutolength((AutolengthProc*)RealSave_Town, t); + SlAutolength(RealSave_Town, t); } } diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index 5e76094215..8885b129e2 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -1316,7 +1316,7 @@ void Save_VENC() return; } - SlAutolength([](void *) { + SlAutolength([]() { int types[4] = {}; int total = 0; for (Vehicle *v : Vehicle::Iterate()) { @@ -1377,7 +1377,7 @@ void Save_VENC() SlWriteUint32(a->index); SlWriteUint16(a->acache.cached_max_range); } - }, nullptr); + }); } void Load_VENC() @@ -1610,7 +1610,7 @@ void Save_VLKA() for (Train *t : Train::Iterate()) { if (t->lookahead != nullptr) { SlSetArrayIndex(t->index); - SlAutolength((AutolengthProc*) RealSave_VLKA, t->lookahead.get()); + SlAutolength(RealSave_VLKA, t->lookahead.get()); } } } From 11eebdc5dd3f92f2fbb0aecaf7b1c7619d7366e9 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 21:50:52 +0100 Subject: [PATCH 087/107] Saveload: Table format sub-struct support --- src/sl/bridge_signal_sl.cpp | 4 +- src/sl/cargopacket_sl.cpp | 4 +- src/sl/cheat_sl.cpp | 6 +- src/sl/debug_sl.cpp | 4 +- src/sl/industry_sl.cpp | 4 +- src/sl/newgrf_sl.cpp | 8 +- src/sl/newsignals_sl.cpp | 4 +- src/sl/saveload.cpp | 202 +++++++++++++++++++++++++----- src/sl/saveload.h | 17 ++- src/sl/saveload_buffer.h | 7 ++ src/sl/saveload_types.h | 139 +++++++++++++++++--- src/sl/tracerestrict_sl.cpp | 16 +-- src/sl/train_speed_adaptation.cpp | 4 +- src/sl/tunnel_sl.cpp | 4 +- 14 files changed, 340 insertions(+), 83 deletions(-) diff --git a/src/sl/bridge_signal_sl.cpp b/src/sl/bridge_signal_sl.cpp index 0a06688fb7..fab8e93da4 100644 --- a/src/sl/bridge_signal_sl.cpp +++ b/src/sl/bridge_signal_sl.cpp @@ -18,7 +18,7 @@ static const NamedSaveLoad _long_bridge_signal_storage_desc[] = { static void Load_XBSS() { - std::vector slt = SlTableHeaderOrRiff(_long_bridge_signal_storage_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_long_bridge_signal_storage_desc); int index; while ((index = SlIterateArray()) != -1) { @@ -29,7 +29,7 @@ static void Load_XBSS() static void Save_XBSS() { - std::vector slt = SlTableHeader(_long_bridge_signal_storage_desc); + SaveLoadTableData slt = SlTableHeader(_long_bridge_signal_storage_desc); for (auto &it : _long_bridge_signal_sim_map) { LongBridgeSignalStorage &lbss = it.second; diff --git a/src/sl/cargopacket_sl.cpp b/src/sl/cargopacket_sl.cpp index 542ba1e897..c2fc2e6636 100644 --- a/src/sl/cargopacket_sl.cpp +++ b/src/sl/cargopacket_sl.cpp @@ -181,7 +181,7 @@ NamedSaveLoadTable GetCargoPacketDesc() */ static void Save_CAPA() { - std::vector slt = SlTableHeader(GetCargoPacketDesc()); + SaveLoadTableData slt = SlTableHeader(GetCargoPacketDesc()); for (CargoPacket *cp : CargoPacket::Iterate()) { SlSetArrayIndex(cp->index); @@ -194,7 +194,7 @@ static void Save_CAPA() */ static void Load_CAPA() { - std::vector slt = SlTableHeaderOrRiff(GetCargoPacketDesc()); + SaveLoadTableData slt = SlTableHeaderOrRiff(GetCargoPacketDesc()); int index; while ((index = SlIterateArray()) != -1) { diff --git a/src/sl/cheat_sl.cpp b/src/sl/cheat_sl.cpp index 1aa78bb343..3b5df34315 100644 --- a/src/sl/cheat_sl.cpp +++ b/src/sl/cheat_sl.cpp @@ -80,7 +80,7 @@ std::vector GetCheatsDesc(bool save) { */ static void Save_CHTS() { - std::vector slt = SlTableHeader(GetCheatsDesc(true)); + SaveLoadTableData slt = SlTableHeader(GetCheatsDesc(true)); SlSetArrayIndex(0); SlObjectSaveFiltered(&_cheats, slt); @@ -105,7 +105,7 @@ static void Load_CHTS() }; UnknownCheatHandler uch{}; - std::vector slt = SlTableHeader(GetCheatsDesc(false), &uch); + SaveLoadTableData slt = SlTableHeader(GetCheatsDesc(false), &uch); if (SlIterateArray() == -1) return; SlObjectLoadFiltered(&_cheats, slt); @@ -114,7 +114,7 @@ static void Load_CHTS() } } else { size_t count = SlGetFieldLength(); - std::vector slt = SlTableHeaderOrRiff(GetCheatsDesc(false)); + SaveLoadTableData slt = SlTableHeaderOrRiff(GetCheatsDesc(false)); /* Cheats were added over the years without a savegame bump. They are * stored as 2 SLE_BOOLs per entry. "count" indicates how many SLE_BOOLs diff --git a/src/sl/debug_sl.cpp b/src/sl/debug_sl.cpp index 75e26bdf55..45179e8e26 100644 --- a/src/sl/debug_sl.cpp +++ b/src/sl/debug_sl.cpp @@ -85,7 +85,7 @@ static void Load_DBGD() NSLT("config", SLEG_SSTR(_loadgame_DBGC_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), NSLT("log", SLEG_SSTR(_loadgame_DBGL_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), }; - SlLoadTableOrRiffFiltered(nsl); + SlLoadTableObjectChunk(nsl); } static void Check_DBGD() @@ -99,7 +99,7 @@ static void Check_DBGD() NSLT("config", SLEG_SSTR(_load_check_data.debug_config_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), NSLT("log", SLEG_SSTR(_load_check_data.debug_log_data, SLE_STR | SLF_ALLOW_CONTROL | SLF_ALLOW_NEWLINE)), }; - SlLoadTableOrRiffFiltered(nsl); + SlLoadTableObjectChunk(nsl); } extern const ChunkHandler debug_chunk_handlers[] = { diff --git a/src/sl/industry_sl.cpp b/src/sl/industry_sl.cpp index ada384acee..a64e01a1ee 100644 --- a/src/sl/industry_sl.cpp +++ b/src/sl/industry_sl.cpp @@ -167,7 +167,7 @@ static const NamedSaveLoad _industrytype_builder_desc[] = { /** Save industry-type build data. */ static void Save_ITBL() { - std::vector sld = SlTableHeader(_industrytype_builder_desc); + SaveLoadTableData sld = SlTableHeader(_industrytype_builder_desc); for (int i = 0; i < NUM_INDUSTRYTYPES; i++) { SlSetArrayIndex(i); @@ -178,7 +178,7 @@ static void Save_ITBL() /** Load industry-type build data. */ static void Load_ITBL() { - std::vector sld = SlTableHeaderOrRiff(_industrytype_builder_desc); + SaveLoadTableData sld = SlTableHeaderOrRiff(_industrytype_builder_desc); for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { _industry_builder.builddata[it].Reset(); diff --git a/src/sl/newgrf_sl.cpp b/src/sl/newgrf_sl.cpp index 97dd6fb857..7c6cd96ba5 100644 --- a/src/sl/newgrf_sl.cpp +++ b/src/sl/newgrf_sl.cpp @@ -36,7 +36,7 @@ static const NamedSaveLoad _newgrf_mapping_desc_new[] = { */ void Save_NewGRFMapping(const OverrideManagerBase &mapping) { - std::vector sld = SlTableHeader(_newgrf_mapping_desc_new); + SaveLoadTableData sld = SlTableHeader(_newgrf_mapping_desc_new); for (uint i = 0; i < mapping.GetMaxMapping(); i++) { if (mapping.mappings[i].grfid == 0 && @@ -60,7 +60,7 @@ void Load_NewGRFMapping(OverrideManagerBase &mapping) uint max_id = mapping.GetMaxMapping(); SaveLoadTable slt; - std::vector sld; + SaveLoadTableData sld; if (SlXvIsFeaturePresent(XSLFI_NEWGRF_ENTITY_EXTRA) || SlIsTableChunk()) { sld = SlTableHeaderOrRiff(_newgrf_mapping_desc_new); @@ -91,7 +91,7 @@ static const NamedSaveLoad _grfconfig_desc[] = { static void Save_NGRF() { - std::vector sld = SlTableHeader(_grfconfig_desc); + SaveLoadTableData sld = SlTableHeader(_grfconfig_desc); int index = 0; for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { @@ -108,7 +108,7 @@ static void Load_NGRF_common(GRFConfig *&grfconfig) if (SlXvIsFeaturePresent(XSLFI_TABLE_NEWGRF_SL, 1, 1)) { SlLoadTableWithArrayLengthPrefixesMissing(); } - std::vector sld = SlTableHeaderOrRiff(_grfconfig_desc); + SaveLoadTableData sld = SlTableHeaderOrRiff(_grfconfig_desc); ClearGRFConfigList(&grfconfig); while (SlIterateArray() != -1) { GRFConfig *c = new GRFConfig(); diff --git a/src/sl/newsignals_sl.cpp b/src/sl/newsignals_sl.cpp index bfaef5bc2b..1c983de524 100644 --- a/src/sl/newsignals_sl.cpp +++ b/src/sl/newsignals_sl.cpp @@ -21,7 +21,7 @@ static const NamedSaveLoad _new_signal_style_mapping_desc[] = { static void Save_NSID() { - std::vector slt = SlTableHeader(_new_signal_style_mapping_desc); + SaveLoadTableData slt = SlTableHeader(_new_signal_style_mapping_desc); int index = 0; for (NewSignalStyleMapping &it : _new_signal_style_mapping) { @@ -35,7 +35,7 @@ static void Load_NSID() _new_signal_style_mapping.fill({}); if (SlIsTableChunk()) { - std::vector slt = SlTableHeader(_new_signal_style_mapping_desc); + SaveLoadTableData slt = SlTableHeader(_new_signal_style_mapping_desc); int index; while ((index = SlIterateArray()) != -1) { diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 1ad1459931..1f77e122e8 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -230,6 +230,19 @@ size_t MemoryDumper::GetSize() const return this->completed_block_bytes + (this->bufe ? (MEMORY_CHUNK_SIZE - (this->bufe - this->buf)) : 0); } +/** + * Get the size of the memory dump made so far. + * @return The size. + */ +size_t MemoryDumper::GetWriteOffsetGeneric() const +{ + if (this->saved_buf != nullptr) { + return this->buf - this->autolen_buf; + } else { + return this->GetSize(); + } +} + enum SaveLoadBlockFlags { SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING, ///< Table chunk arrays were incorrectly saved without the length prefix, skip reading the length prefix on load }; @@ -1886,6 +1899,11 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) case SL_WRITEBYTE: return 1; // a uint8_t is logically of size 1 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription()); + + case SL_STRUCT: + case SL_STRUCTLIST: + NOT_REACHED(); // SlAutolength or similar should be used for sub-structs + default: NOT_REACHED(); } return 0; @@ -1906,6 +1924,8 @@ static void SlFilterObjectMember(const SaveLoad &sld, std::vector &sav case SL_RING: case SL_STDSTR: case SL_VARVEC: + case SL_STRUCT: + case SL_STRUCTLIST: /* CONDITIONAL saveload types depend on the savegame version */ if (!SlIsObjectValidInSavegame(sld)) return; @@ -1921,6 +1941,8 @@ static void SlFilterObjectMember(const SaveLoad &sld, std::vector &sav case SL_REFLIST: case SL_PTRRING: case SL_VEC: + case SL_STRUCT: + case SL_STRUCTLIST: break; /* non-ptr types do not require SLA_PTRS or SLA_NULL actions */ @@ -2032,6 +2054,51 @@ bool SlObjectMemberGeneric(void *object, const SaveLoad &sld) } break; + case SL_STRUCT: + case SL_STRUCTLIST: + switch (action) { + case SLA_SAVE: { + if (sld.cmd == SL_STRUCT) { + /* Number of structs written in the savegame: write a value of 1, change to zero later if nothing after this was written */ + _sl.dumper->WriteByte(1); + size_t offset = _sl.dumper->GetWriteOffsetGeneric(); + sld.struct_handler->Save(object); + if (offset == _sl.dumper->GetWriteOffsetGeneric()) { + /* Nothing was actaully written, so it's safe to change the 1 above to 0 */ + _sl.dumper->UnWriteByte(); // This is fine iff nothing has been written since the WriteByte(1) + _sl.dumper->RawWriteByte(0); + } + } else { + sld.struct_handler->Save(object); + } + break; + } + + case SLA_LOAD_CHECK: { + if (sld.cmd == SL_STRUCT && SlIsTableChunk()) { + if (SlGetStructListLength(1) == 0) break; + } + sld.struct_handler->LoadCheck(object); + break; + } + + case SLA_LOAD: { + if (sld.cmd == SL_STRUCT && SlIsTableChunk()) { + if (SlGetStructListLength(1) == 0) break; + } + sld.struct_handler->Load(object); + break; + } + + case SLA_PTRS: + sld.struct_handler->FixPointers(object); + break; + + case SLA_NULL: break; + default: NOT_REACHED(); + } + break; + /* SL_WRITEBYTE writes a value to the savegame to identify the type of an object. * When loading, the value is read explicitly with SlReadByte() to determine which * object description to use. */ @@ -2141,34 +2208,18 @@ bool SlIsTableChunk() void SlSkipTableHeader() { + uint sub_tables = 0; while (true) { uint8_t type = SlReadByte(); if (type == SLE_FILE_END) break; + if ((type & SLE_FILE_TYPE_MASK) == SLE_FILE_STRUCT) sub_tables++; + SlString(nullptr, 0, SLE_FILE_STRING | SLE_VAR_NULL); } -} - -/** - * Calculate the size of the table header. - * @param slt The SaveLoad table with objects to save/load. - * @return size of given object. - */ -static size_t SlCalcTableHeader(const NamedSaveLoadTable &slt) -{ - size_t length = 0; - - for (auto &nsld : slt) { - if (StrEmpty(nsld.name) || !SlIsObjectValidInSavegame(nsld.save_load)) continue; - - length += 1 + SlCalcStringLen(&nsld.name, 0, SLE_STR); + for (uint i = 0; i < sub_tables; i++) { + SlSkipTableHeader(); } - - length++; // End-of-list entry. - - /* SL_STRUCTLIST, SL_STRUCT not currently implemented */ - - return length; } /** @@ -2198,22 +2249,55 @@ static uint8_t GetSavegameTableFileType(const SaveLoad &sld) case SL_WRITEBYTE: return SLE_FILE_U8; + case SL_STRUCT: + case SL_STRUCTLIST: + return SLE_FILE_STRUCT | SLE_FILE_HAS_LENGTH_FIELD; + default: NOT_REACHED(); } } +/** + * Handler that is assigned when there is a struct read in the savegame which + * is not known to the code. This means we are going to skip it. + */ +class SaveLoadSkipStructHandler : public SaveLoadStructHandler { + void Save(void *) const override + { + NOT_REACHED(); + } + + void Load(void *object) const override + { + size_t length = SlGetStructListLength(UINT32_MAX); + for (; length > 0; length--) { + SlObjectLoadFiltered(object, this->GetLoadDescription()); + } + } + + void LoadCheck(void *object) const override + { + this->Load(object); + } + + NamedSaveLoadTable GetDescription() const override + { + return {}; + } +}; + /** * Save or Load a table header. * @note a table-header can never contain more than 65535 fields. * @param slt The NamedSaveLoad table with objects to save/load. * @return The ordered SaveLoad array to use. */ -std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler) +SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler) { /* You can only use SlTableHeader if you are a CH_TABLE. */ assert(_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); - std::vector saveloads; + SaveLoadTableData saveloads; switch (_sl.action) { case SLA_LOAD_CHECK: @@ -2261,15 +2345,20 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp DEBUG(sl, _sl.action == SLA_LOAD ? 2 : 6, "Field '%s' of type 0x%02X not found, skipping", key.c_str(), type); SaveLoadType saveload_type; + SaveLoadStructHandler *struct_handler = nullptr; switch (type & SLE_FILE_TYPE_MASK) { case SLE_FILE_STRING: /* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */ saveload_type = SL_STDSTR; break; - case SLE_FILE_STRUCT: - SlErrorCorrupt("SLE_FILE_STRUCT not supported yet"); + case SLE_FILE_STRUCT: { + saveload_type = SL_STRUCTLIST; + auto handler = std::make_unique(); + struct_handler = handler.get(); + saveloads.struct_handlers.push_back(std::move(handler)); break; + } default: saveload_type = (type & SLE_FILE_HAS_LENGTH_FIELD) ? SL_ARR : SL_VAR; @@ -2277,7 +2366,7 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp } /* We don't know this field, so read to nothing. */ - saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_TABLE_UNKNOWN, nullptr, SlXvFeatureTest() }); + saveloads.push_back({ true, saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, SLTAG_TABLE_UNKNOWN, nullptr, SlXvFeatureTest(), struct_handler }); continue; } @@ -2292,17 +2381,28 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp SlErrorCorrupt("Field type is different than expected"); } saveloads.push_back(*sld_it->save_load); + + if ((type & SLE_FILE_TYPE_MASK) == SLE_FILE_STRUCT) { + std::unique_ptr handler = saveloads.back().struct_handler_factory(); + saveloads.back().struct_handler = handler.get(); + saveloads.struct_handlers.push_back(std::move(handler)); + } } - /* SL_STRUCTLIST, SL_STRUCT not currently implemented */ + for (auto &sld : saveloads) { + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + sld.struct_handler->table_data = SlTableHeader(sld.struct_handler->GetDescription()); + } + } break; } case SLA_SAVE: { - /* Automatically calculate the length? */ - if (_sl.need_length != NL_NONE) { - SlSetLength(SlCalcTableHeader(slt)); + const NeedLength orig_need_length = _sl.need_length; + if (orig_need_length != NL_NONE) { + _sl.need_length = NL_NONE; + _sl.dumper->StartAutoLength(); } for (auto &nsld : slt) { @@ -2319,7 +2419,21 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp /* Add an end-of-header marker. */ SlWriteByte(SLE_FILE_END); - /* SL_STRUCTLIST, SL_STRUCT not currently implemented */ + for (auto &sld : saveloads) { + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + std::unique_ptr handler = sld.struct_handler_factory(); + sld.struct_handler = handler.get(); + sld.struct_handler->table_data = SlTableHeader(sld.struct_handler->GetDescription()); + saveloads.struct_handlers.push_back(std::move(handler)); + } + } + + if (orig_need_length != NL_NONE) { + auto result = _sl.dumper->StopAutoLength(); + _sl.need_length = orig_need_length; + SlSetLength(result.size()); + _sl.dumper->CopyBytes(result); + } break; } @@ -2330,11 +2444,11 @@ std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSp return saveloads; } -std::vector SlTableHeaderOrRiff(const NamedSaveLoadTable &slt) +SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt) { if (SlIsTableChunk()) return SlTableHeader(slt); - std::vector saveloads; + SaveLoadTableData saveloads; for (auto &nsld : slt) { if ((nsld.nsl_flags & NSLF_TABLE_ONLY) != 0) continue; SlFilterObjectMember(nsld.save_load, saveloads); @@ -2363,6 +2477,28 @@ void SlLoadTableWithArrayLengthPrefixesMissing() SetBit(_sl.block_flags, SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING); } +/** + * Set the length of this list. + * @param The length of the list. + */ +void SlSetStructListLength(size_t length) +{ + SlWriteArrayLength(length); +} + +/** + * Get the length of this list; if it exceeds the limit, error out. + * @param limit The maximum size the list can be. + * @return The length of the list. + */ +size_t SlGetStructListLength(size_t limit) +{ + size_t length = SlReadArrayLength(); + if (length > limit) SlErrorCorrupt("List exceeds storage size"); + + return length; +} + void SlSkipChunkContents() { if (SlIsTableChunk()) SlSkipTableHeader(); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 18c3ae9097..1fb1d74373 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1092,12 +1092,15 @@ struct TableHeaderSpecialHandler { bool SlIsTableChunk(); void SlSkipTableHeader(); -std::vector SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); -std::vector SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); +SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); +SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); void SlSaveTableObjectChunk(const SaveLoadTable &slt); void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); void SlLoadTableWithArrayLengthPrefixesMissing(); +void SlSetStructListLength(size_t length); +size_t SlGetStructListLength(size_t limit); + void SlSkipChunkContents(); inline void SlSaveTableObjectChunk(const NamedSaveLoadTable &slt) @@ -1105,6 +1108,16 @@ inline void SlSaveTableObjectChunk(const NamedSaveLoadTable &slt) SlSaveTableObjectChunk(SlTableHeader(slt)); } +inline void SlLoadTableObjectChunk(const NamedSaveLoadTable &slt) +{ + SlLoadTableOrRiffFiltered(SlTableHeader(slt)); +} + +inline void SlLoadTableObjectChunk(const SaveLoadTable &slt) +{ + SlLoadTableOrRiffFiltered(slt); +} + inline void SlLoadTableOrRiffFiltered(const NamedSaveLoadTable &slt) { SlLoadTableOrRiffFiltered(SlTableHeaderOrRiff(slt)); diff --git a/src/sl/saveload_buffer.h b/src/sl/saveload_buffer.h index c45eb6ae67..98b2ea6769 100644 --- a/src/sl/saveload_buffer.h +++ b/src/sl/saveload_buffer.h @@ -256,6 +256,12 @@ struct MemoryDumper { this->CopyBytes(buffer.data(), buffer.size()); } + /** For limited/special purposes only */ + inline void UnWriteByte() + { + this->buf--; + } + inline void RawWriteByte(uint8_t b) { *this->buf++ = b; @@ -331,6 +337,7 @@ struct MemoryDumper { void Flush(SaveFilter &writer); size_t GetSize() const; + size_t GetWriteOffsetGeneric() const; void StartAutoLength(); std::span StopAutoLength(); bool IsAutoLengthActive() const { return this->saved_buf != nullptr; } diff --git a/src/sl/saveload_types.h b/src/sl/saveload_types.h index 3235dc3818..93a7a9774d 100644 --- a/src/sl/saveload_types.h +++ b/src/sl/saveload_types.h @@ -103,26 +103,30 @@ typedef uint32_t VarType; /** Type of data saved. */ enum SaveLoadTypes { - SL_VAR = 0, ///< Save/load a variable. - SL_REF = 1, ///< Save/load a reference. - SL_ARR = 2, ///< Save/load a fixed-size array of #SL_VAR elements. - SL_STR = 3, ///< Save/load a string. - SL_REFLIST = 4, ///< Save/load a list of #SL_REF elements. - SL_RING = 5, ///< Save/load a ring of #SL_VAR elements. - SL_VEC = 6, ///< Save/load a vector of #SL_REF elements. - SL_STDSTR = 7, ///< Save/load a std::string. + SL_VAR = 0, ///< Save/load a variable. + SL_REF, ///< Save/load a reference. + SL_ARR, ///< Save/load a fixed-size array of #SL_VAR elements. + SL_STR, ///< Save/load a string. + SL_REFLIST, ///< Save/load a list of #SL_REF elements. + SL_RING, ///< Save/load a ring of #SL_VAR elements. + SL_VEC, ///< Save/load a vector of #SL_REF elements. + SL_STDSTR, ///< Save/load a std::string. + SL_PTRRING, ///< Save/load a ring of #SL_REF elements. + SL_VARVEC, ///< Save/load a primitive type vector. + + SL_STRUCT, ///< Save/load a struct. + SL_STRUCTLIST, ///< Save/load a list of structs. /* non-normal save-load types */ - SL_WRITEBYTE = 8, - SL_VEH_INCLUDE = 9, - SL_ST_INCLUDE = 10, - - SL_PTRRING = 13, ///< Save/load a ring of #SL_REF elements. - SL_VARVEC = 14, ///< Save/load a primitive type vector. + SL_WRITEBYTE, + SL_VEH_INCLUDE, + SL_ST_INCLUDE, }; typedef uint8_t SaveLoadType; ///< Save/load type. @see SaveLoadTypes +using SaveLoadStructHandlerFactory = std::unique_ptr (*)(); + /** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ struct SaveLoad { bool global; ///< should we load a global variable or a non-global one @@ -132,12 +136,18 @@ struct SaveLoad { SaveLoadVersion version_from; ///< save/load the variable starting from this savegame version SaveLoadVersion version_to; ///< save/load the variable until this savegame version uint16_t label_tag; ///< for labelling purposes - /* NOTE: This element either denotes the address of the variable for a global - * variable, or the offset within a struct which is then bound to a variable - * during runtime. Decision on which one to use is controlled by the function - * that is called to save it. address: global=true, offset: global=false */ - void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) + + union { + /* NOTE: This element either denotes the address of the variable for a global + * variable, or the offset within a struct which is then bound to a variable + * during runtime. Decision on which one to use is controlled by the function + * that is called to save it. address: global=true, offset: global=false */ + void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) + SaveLoadStructHandlerFactory struct_handler_factory; ///< factory function pointer for SaveLoadStructHandler + }; + SlXvFeatureTest ext_feature_test; ///< extended feature test + SaveLoadStructHandler *struct_handler = nullptr; }; inline constexpr SaveLoad SLTAG(uint16_t label_tag, SaveLoad save_load) @@ -175,4 +185,95 @@ inline constexpr NamedSaveLoad NSLT(const char *name, SaveLoad save_load) return { name, save_load, NSLF_TABLE_ONLY }; } +inline constexpr NamedSaveLoad NSLT_STRUCT(const char *name, SaveLoadStructHandlerFactory factory, SaveLoadVersion from = SL_MIN_VERSION, SaveLoadVersion to = SL_MAX_VERSION, SlXvFeatureTest extver = {}) +{ + return { name, SaveLoad { true, SL_STRUCT, SLE_FILE_STRUCT, 0, from, to, SLTAG_DEFAULT, { .struct_handler_factory = factory }, extver }, NSLF_TABLE_ONLY }; +} + +template +inline constexpr NamedSaveLoad NSLT_STRUCT(const char *name, SaveLoadVersion from = SL_MIN_VERSION, SaveLoadVersion to = SL_MAX_VERSION, SlXvFeatureTest extver = {}) +{ + SaveLoadStructHandlerFactory factory = []() -> std::unique_ptr { + return std::make_unique(); + }; + return NSLT_STRUCT(name, factory, from, to, extver); +} + +inline constexpr NamedSaveLoad NSLT_STRUCTLIST(const char *name, SaveLoadStructHandlerFactory factory, SaveLoadVersion from = SL_MIN_VERSION, SaveLoadVersion to = SL_MAX_VERSION, SlXvFeatureTest extver = {}) +{ + return { name, SaveLoad { true, SL_STRUCTLIST, SLE_FILE_STRUCT, 0, from, to, SLTAG_DEFAULT, { .struct_handler_factory = factory }, extver }, NSLF_TABLE_ONLY }; +} + +template +inline constexpr NamedSaveLoad NSLT_STRUCTLIST(const char *name, SaveLoadVersion from = SL_MIN_VERSION, SaveLoadVersion to = SL_MAX_VERSION, SlXvFeatureTest extver = {}) +{ + SaveLoadStructHandlerFactory factory = []() -> std::unique_ptr { + return std::make_unique(); + }; + return NSLT_STRUCTLIST(name, factory, from, to, extver); +} + +struct SaveLoadTableData : public std::vector { + std::vector> struct_handlers; +}; + +/** Handler for saving/loading a SL_STRUCT/SL_STRUCTLIST. */ +class SaveLoadStructHandler { +public: + SaveLoadTableData table_data; + + virtual ~SaveLoadStructHandler() = default; + + /** + * Get the (static) description of the fields in the savegame. + */ + virtual NamedSaveLoadTable GetDescription() const = 0; + + /** + * Get the (current) description of the fields in the savegame. + */ + SaveLoadTable GetLoadDescription() const { return this->table_data; } + + /** + * Save the object to disk. + * @param object The object to store. + */ + virtual void Save([[maybe_unused]] void *object) const {} + + /** + * Load the object from disk. + * @param object The object to load. + */ + virtual void Load([[maybe_unused]] void *object) const {} + + /** + * Similar to load, but used only to validate savegames. + * @param object The object to load. + */ + virtual void LoadCheck([[maybe_unused]] void *object) const {} + + /** + * A post-load callback to fix #SL_REF integers into pointers. + * @param object The object to fix. + */ + virtual void FixPointers([[maybe_unused]] void *object) const {} +}; + + +template +class TypedSaveLoadStructHandler : public SaveLoadStructHandler { +public: + void Save([[maybe_unused]] TObject *object) const {} + void Save(void *object) const override { static_cast(this)->Save(static_cast(object)); } + + void Load([[maybe_unused]] TObject *object) const {} + void Load(void *object) const override { static_cast(this)->Load(static_cast(object)); } + + void LoadCheck([[maybe_unused]] TObject *object) const {} + void LoadCheck(void *object) const override { static_cast(this)->LoadCheck(static_cast(object)); } + + void FixPointers([[maybe_unused]] TObject *object) const {} + void FixPointers(void *object) const override { static_cast(this)->FixPointers(static_cast(object)); } +}; + #endif /* SL_SAVELOAD_TYPES_H */ diff --git a/src/sl/tracerestrict_sl.cpp b/src/sl/tracerestrict_sl.cpp index 756c2540b7..a4ec6f6980 100644 --- a/src/sl/tracerestrict_sl.cpp +++ b/src/sl/tracerestrict_sl.cpp @@ -23,7 +23,7 @@ static const NamedSaveLoad _trace_restrict_mapping_desc[] = { */ static void Load_TRRM() { - std::vector slt = SlTableHeaderOrRiff(_trace_restrict_mapping_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_trace_restrict_mapping_desc); int index; while ((index = SlIterateArray()) != -1) { @@ -37,7 +37,7 @@ static void Load_TRRM() */ static void Save_TRRM() { - std::vector slt = SlTableHeader(_trace_restrict_mapping_desc); + SaveLoadTableData slt = SlTableHeader(_trace_restrict_mapping_desc); for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin(); iter != _tracerestrictprogram_mapping.end(); ++iter) { @@ -55,7 +55,7 @@ static const NamedSaveLoad _trace_restrict_program_desc[] = { */ static void Load_TRRP() { - std::vector slt = SlTableHeaderOrRiff(_trace_restrict_program_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_trace_restrict_program_desc); int index; while ((index = SlIterateArray()) != -1) { @@ -111,7 +111,7 @@ static void Load_TRRP() */ static void Save_TRRP() { - std::vector slt = SlTableHeader(_trace_restrict_program_desc); + SaveLoadTableData slt = SlTableHeader(_trace_restrict_program_desc); for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) { SlSetArrayIndex(prog->index); @@ -132,7 +132,7 @@ static const NamedSaveLoad _trace_restrict_slot_desc[] = { */ static void Load_TRRS() { - std::vector slt = SlTableHeaderOrRiff(_trace_restrict_slot_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_trace_restrict_slot_desc); int index; while ((index = SlIterateArray()) != -1) { @@ -147,7 +147,7 @@ static void Load_TRRS() */ static void Save_TRRS() { - std::vector slt = SlTableHeader(_trace_restrict_slot_desc); + SaveLoadTableData slt = SlTableHeader(_trace_restrict_slot_desc); for (TraceRestrictSlot *slot : TraceRestrictSlot::Iterate()) { SlSetArrayIndex(slot->index); @@ -166,7 +166,7 @@ static const NamedSaveLoad _trace_restrict_counter_desc[] = { */ static void Load_TRRC() { - std::vector slt = SlTableHeaderOrRiff(_trace_restrict_counter_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_trace_restrict_counter_desc); int index; while ((index = SlIterateArray()) != -1) { @@ -180,7 +180,7 @@ static void Load_TRRC() */ static void Save_TRRC() { - std::vector slt = SlTableHeader(_trace_restrict_counter_desc); + SaveLoadTableData slt = SlTableHeader(_trace_restrict_counter_desc); for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { SlSetArrayIndex(ctr->index); diff --git a/src/sl/train_speed_adaptation.cpp b/src/sl/train_speed_adaptation.cpp index 93817351ed..4be27b13e9 100644 --- a/src/sl/train_speed_adaptation.cpp +++ b/src/sl/train_speed_adaptation.cpp @@ -25,7 +25,7 @@ static const NamedSaveLoad _train_speed_adaptation_map_desc[] = { static void Load_TSAS() { const bool table_mode = SlIsTableChunk(); - std::vector slt = SlTableHeaderOrRiff(_train_speed_adaptation_map_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_train_speed_adaptation_map_desc); int index; SignalSpeedType data; @@ -40,7 +40,7 @@ static void Load_TSAS() static void Save_TSAS() { - std::vector slt = SlTableHeader(_train_speed_adaptation_map_desc); + SaveLoadTableData slt = SlTableHeader(_train_speed_adaptation_map_desc); int index = 0; for (auto &it : _signal_speeds) { diff --git a/src/sl/tunnel_sl.cpp b/src/sl/tunnel_sl.cpp index 43461b8e55..2b740aa867 100644 --- a/src/sl/tunnel_sl.cpp +++ b/src/sl/tunnel_sl.cpp @@ -25,7 +25,7 @@ static const NamedSaveLoad _tunnel_desc[] = { static void Save_TUNN() { - std::vector slt = SlTableHeader(_tunnel_desc); + SaveLoadTableData slt = SlTableHeader(_tunnel_desc); for (Tunnel *tunnel : Tunnel::Iterate()) { SlSetArrayIndex(tunnel->index); @@ -35,7 +35,7 @@ static void Save_TUNN() static void Load_TUNN() { - std::vector slt = SlTableHeaderOrRiff(_tunnel_desc); + SaveLoadTableData slt = SlTableHeaderOrRiff(_tunnel_desc); int index; while ((index = SlIterateArray()) != -1) { From e0352b8161169614037fc213cb87ff166ac51606 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Jul 2024 21:52:04 +0100 Subject: [PATCH 088/107] Saveload: Use table format for animated tiles --- src/sl/animated_tile_sl.cpp | 69 ++++++++++++++++++++++++++++++------- src/sl/extended_ver_sl.cpp | 2 +- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/sl/animated_tile_sl.cpp b/src/sl/animated_tile_sl.cpp index aef1f9e7b0..b0eaca342d 100644 --- a/src/sl/animated_tile_sl.cpp +++ b/src/sl/animated_tile_sl.cpp @@ -16,21 +16,59 @@ #include "../safeguards.h" +using AnimatedTilePair = std::pair; + +struct AnimatedTileStructHandler : public SaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + static const NamedSaveLoad _anim_tiles_sub_desc[] = { + NSLT("tile", SLTAG(SLTAG_CUSTOM_START, SLE_VAR(AnimatedTilePair, first, SLE_UINT32))), + NSLT("speed", SLTAG(SLTAG_CUSTOM_START + 1, SLE_VAR(AnimatedTilePair, second.speed, SLE_UINT8))), + }; + return _anim_tiles_sub_desc; + } + + void Save([[maybe_unused]] void *object) const override + { + uint count = 0; + for (const auto &it : _animated_tiles) { + if (!it.second.pending_deletion) count++; + } + SlSetStructListLength(count); + for (const auto &it : _animated_tiles) { + if (it.second.pending_deletion) continue; + SlWriteUint32(it.first); + SlWriteByte(it.second.speed); + } + } + + void Load([[maybe_unused]] void *object) const override + { + auto slt = this->GetLoadDescription(); + if (slt.size() != 2 || slt[0].label_tag != SLTAG_CUSTOM_START || slt[1].label_tag != SLTAG_CUSTOM_START + 1) { + SlErrorCorrupt("Table format ANIT chunk fields not as expected"); + } + + size_t count = SlGetStructListLength(MAX_MAP_TILES); + for (size_t i = 0; i < count; i++) { + TileIndex tile = SlReadUint32(); + AnimatedTileInfo info = {}; + info.speed = SlReadByte(); + _animated_tiles[tile] = info; + } + } +}; + +static const NamedSaveLoad _anim_tiles_desc[] = { + NSLT_STRUCTLIST("animated_tiles"), +}; + /** * Save the ANIT chunk. */ static void Save_ANIT() { - uint count = 0; - for (const auto &it : _animated_tiles) { - if (!it.second.pending_deletion) count++; - } - SlSetLength(count * 5); - for (const auto &it : _animated_tiles) { - if (it.second.pending_deletion) continue; - SlWriteUint32(it.first); - SlWriteByte(it.second.speed); - } + SlSaveTableObjectChunk(_anim_tiles_desc); } /** @@ -38,6 +76,14 @@ static void Save_ANIT() */ static void Load_ANIT() { + _animated_tiles.clear(); + + if (SlIsTableChunk()) { + if (SlXvIsFeatureMissing(XSLFI_ANIMATED_TILE_EXTRA, 2)) SlErrorCorrupt("Table format ANIT chunk without XSLFI_ANIMATED_TILE_EXTRA v2"); + SlLoadTableObjectChunk(_anim_tiles_desc); + return; + } + /* Before version 80 we did NOT have a variable length animated tile table */ if (IsSavegameVersionBefore(SLV_80)) { /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ @@ -51,7 +97,6 @@ static void Load_ANIT() return; } - _animated_tiles.clear(); if (SlXvIsFeaturePresent(XSLFI_ANIMATED_TILE_EXTRA)) { uint count = (uint)SlGetFieldLength() / 5; for (uint i = 0; i < count; i++) { @@ -73,7 +118,7 @@ static void Load_ANIT() * the animated tile table. */ static const ChunkHandler animated_tile_chunk_handlers[] = { - { 'ANIT', Save_ANIT, Load_ANIT, nullptr, nullptr, CH_RIFF }, + { 'ANIT', Save_ANIT, Load_ANIT, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _animated_tile_chunk_handlers(animated_tile_chunk_handlers); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index d38a72f663..eb960cb7cf 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -154,7 +154,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_ONE_WAY_DT_ROAD_STOP, XSCF_NULL, 1, 1, "one_way_dt_road_stop", nullptr, nullptr, nullptr }, { XSLFI_ONE_WAY_ROAD_STATE, XSCF_NULL, 1, 1, "one_way_road_state", nullptr, nullptr, nullptr }, { XSLFI_VENC_CHUNK, XSCF_IGNORABLE_ALL, 0, 1, "venc_chunk", nullptr, nullptr, "VENC" }, - { XSLFI_ANIMATED_TILE_EXTRA, XSCF_NULL, 1, 1, "animated_tile_extra", nullptr, nullptr, nullptr }, + { XSLFI_ANIMATED_TILE_EXTRA, XSCF_NULL, 2, 2, "animated_tile_extra", nullptr, nullptr, nullptr }, { XSLFI_NEWGRF_INFO_EXTRA, XSCF_NULL, 1, 1, "newgrf_info_extra", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "industry_cargo_adj", nullptr, nullptr, nullptr }, { XSLFI_REALISTIC_TRAIN_BRAKING, XSCF_NULL, 11, 11, "realistic_train_braking", nullptr, nullptr, "VLKA" }, From 0bde627c743995ad18bb3fd841f83245b2fe1014 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 00:08:05 +0100 Subject: [PATCH 089/107] Saveload: Use virtual for TypedSaveLoadStructHandler typed variants --- src/sl/saveload_types.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sl/saveload_types.h b/src/sl/saveload_types.h index 93a7a9774d..792ef6744f 100644 --- a/src/sl/saveload_types.h +++ b/src/sl/saveload_types.h @@ -263,16 +263,16 @@ public: template class TypedSaveLoadStructHandler : public SaveLoadStructHandler { public: - void Save([[maybe_unused]] TObject *object) const {} + virtual void Save([[maybe_unused]] TObject *object) const {} void Save(void *object) const override { static_cast(this)->Save(static_cast(object)); } - void Load([[maybe_unused]] TObject *object) const {} + virtual void Load([[maybe_unused]] TObject *object) const {} void Load(void *object) const override { static_cast(this)->Load(static_cast(object)); } - void LoadCheck([[maybe_unused]] TObject *object) const {} + virtual void LoadCheck([[maybe_unused]] TObject *object) const {} void LoadCheck(void *object) const override { static_cast(this)->LoadCheck(static_cast(object)); } - void FixPointers([[maybe_unused]] TObject *object) const {} + virtual void FixPointers([[maybe_unused]] TObject *object) const {} void FixPointers(void *object) const override { static_cast(this)->FixPointers(static_cast(object)); } }; From 38781fb16e6a86a532ddd4c6d748205dbca6ad0c Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 00:26:42 +0100 Subject: [PATCH 090/107] Saveload: Use table format for plans chunk --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/plans_sl.cpp | 78 +++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index eb960cb7cf..e929780ae9 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -101,7 +101,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 2, 2, "tt_wait_in_depot", nullptr, nullptr, nullptr }, { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 5, 5, "auto_timetables", nullptr, nullptr, nullptr }, { XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 2, 2, "vehicle_repair_cost", nullptr, nullptr, nullptr }, - { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 4, 4, "enh_viewport_plans", nullptr, nullptr, "PLAN" }, + { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 5, 5, "enh_viewport_plans", nullptr, nullptr, "PLAN" }, { XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" }, { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 7, 7, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, diff --git a/src/sl/plans_sl.cpp b/src/sl/plans_sl.cpp index f3544b4839..ac9810e57d 100644 --- a/src/sl/plans_sl.cpp +++ b/src/sl/plans_sl.cpp @@ -13,44 +13,78 @@ #include "saveload.h" -/** Description of a plan within the savegame. */ -static const SaveLoad _plan_desc[] = { - SLE_VAR(Plan, owner, SLE_UINT8), - SLE_VAR(Plan, visible, SLE_BOOL), - SLE_VAR(Plan, visible_by_all, SLE_BOOL), - SLE_VAR(Plan, creation_date, SLE_INT32), - SLE_CONDSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 3)), - SLE_CONDSSTR_X(Plan, name, 0, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_20)), - SLE_CONDVAR_X(Plan, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 4)), +struct PlanLineStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + static const NamedSaveLoad _plan_line_sub_desc[] = { + NSLT("tiles", SLE_VARVEC(PlanLine, tiles, SLE_UINT32)), + }; + return _plan_line_sub_desc; + } + + void Save(Plan *p) const override + { + SlSetStructListLength(p->lines.size()); + for (PlanLine *pl : p->lines) { + SlObjectSaveFiltered(pl, this->GetLoadDescription()); + } + } + + void Load(Plan *p) const override + { + size_t line_count = SlGetStructListLength(UINT32_MAX); + p->lines.resize(line_count); + for (size_t i = 0; i < line_count; i++) { + PlanLine *pl = new PlanLine(); + p->lines[i] = pl; + SlObjectLoadFiltered(pl, this->GetLoadDescription()); + pl->UpdateVisualExtents(); + } + } }; -static void RealSave_PLAN(Plan *p) -{ - SlObject(p, _plan_desc); - SlWriteUint32((uint32_t)p->lines.size()); - for (size_t i = 0; i < p->lines.size(); i++) { - PlanLine *pl = p->lines[i]; - SlWriteUint32((uint32_t)pl->tiles.size()); - SlArray(pl->tiles.data(), pl->tiles.size(), SLE_UINT32); - } -} +/** Description of a plan within the savegame. */ +static const NamedSaveLoad _plan_desc[] = { + NSL("owner", SLE_VAR(Plan, owner, SLE_UINT8)), + NSL("visible", SLE_VAR(Plan, visible, SLE_BOOL)), + NSL("visible_by_all", SLE_VAR(Plan, visible_by_all, SLE_BOOL)), + NSL("creation_date", SLE_VAR(Plan, creation_date, SLE_INT32)), + NSL("name", SLE_CONDSSTR_X(Plan, name, SLE_STR, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 3))), + NSL("name", SLE_CONDSSTR_X(Plan, name, SLE_STR, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_20))), + NSL("colour", SLE_CONDVAR_X(Plan, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ENH_VIEWPORT_PLANS, 4))), + NSLT_STRUCTLIST("lines"), +}; /** Save all plans. */ static void Save_PLAN() { + SaveLoadTableData slt = SlTableHeader(_plan_desc); + for (Plan *p : Plan::Iterate()) { SlSetArrayIndex(p->index); - SlAutolength(RealSave_PLAN, p); + SlObjectSaveFiltered(p, slt); } } /** Load all plans. */ static void Load_PLAN() { + SaveLoadTableData slt = SlTableHeaderOrRiff(_plan_desc); + + if (SlIsTableChunk()) { + int index; + while ((index = SlIterateArray()) != -1) { + Plan *p = new (index) Plan(); + SlObjectLoadFiltered(p, slt); + p->SetVisibility(false); + } + return; + } + int index; while ((index = SlIterateArray()) != -1) { Plan *p = new (index) Plan(); - SlObject(p, _plan_desc); + SlObjectLoadFiltered(p, slt); if (SlXvIsFeaturePresent(XSLFI_ENH_VIEWPORT_PLANS, 2)) { const size_t line_count = SlReadUint32(); p->lines.resize(line_count); @@ -90,7 +124,7 @@ static void Load_PLANLINE() /** Chunk handlers related to plans. */ static const ChunkHandler plan_chunk_handlers[] = { - { 'PLAN', Save_PLAN, Load_PLAN, nullptr, nullptr, CH_ARRAY }, + { 'PLAN', Save_PLAN, Load_PLAN, nullptr, nullptr, CH_TABLE }, { 'PLLN', nullptr, Load_PLANLINE, nullptr, nullptr, CH_READONLY }, }; From c7a4c6ba0ea6c5917cc819525985bf241b406f07 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 18:21:08 +0100 Subject: [PATCH 091/107] Saveload: Add helper for null/ptr named save load table handling --- src/sl/saveload.cpp | 15 +++++++++++++++ src/sl/saveload.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 1f77e122e8..464f0771e4 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2456,6 +2456,21 @@ SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt) return saveloads; } +SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTable &slt) +{ + SaveLoadTableData saveloads; + SlFilterNamedSaveLoadTable(slt, saveloads); + for (auto &sld : saveloads) { + if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) { + std::unique_ptr handler = sld.struct_handler_factory(); + sld.struct_handler = handler.get(); + saveloads.struct_handlers.push_back(std::move(handler)); + sld.struct_handler->table_data = SlPrepareNamedSaveLoadTableForPtrOrNull(sld.struct_handler->GetDescription()); + } + } + return saveloads; +} + void SlSaveTableObjectChunk(const SaveLoadTable &slt) { SlSetArrayIndex(0); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 1fb1d74373..c448f6beee 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1094,6 +1094,7 @@ bool SlIsTableChunk(); void SlSkipTableHeader(); SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); +SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTable &slt); void SlSaveTableObjectChunk(const SaveLoadTable &slt); void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); void SlLoadTableWithArrayLengthPrefixesMissing(); From 7bf1cf08659b60ae619fe2a97ab7a02962b391a9 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 18:56:56 +0100 Subject: [PATCH 092/107] Saveload: Add helper to filter named save load table --- src/sl/saveload.cpp | 20 ++++++++++++++++---- src/sl/saveload.h | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 464f0771e4..44ce8427d0 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -1990,6 +1990,21 @@ std::vector SlFilterObject(const SaveLoadTable &slt) return save; } +void SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt, std::vector &save) +{ + for (auto &nsld : nslt) { + if ((nsld.nsl_flags & NSLF_TABLE_ONLY) != 0) continue; + SlFilterObjectMember(nsld.save_load, save); + } +} + +std::vector SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt) +{ + std::vector save; + SlFilterNamedSaveLoadTable(nslt, save); + return save; +} + template bool SlObjectMemberGeneric(void *object, const SaveLoad &sld) { @@ -2449,10 +2464,7 @@ SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt) if (SlIsTableChunk()) return SlTableHeader(slt); SaveLoadTableData saveloads; - for (auto &nsld : slt) { - if ((nsld.nsl_flags & NSLF_TABLE_ONLY) != 0) continue; - SlFilterObjectMember(nsld.save_load, saveloads); - } + SlFilterNamedSaveLoadTable(slt, saveloads); return saveloads; } diff --git a/src/sl/saveload.h b/src/sl/saveload.h index c448f6beee..da75c34c7a 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1080,6 +1080,7 @@ void SlObject(void *object, const SaveLoadTable &slt); bool SlObjectMember(void *object, const SaveLoad &sld); std::vector SlFilterObject(const SaveLoadTable &slt); +std::vector SlFilterNamedSaveLoadTable(const NamedSaveLoadTable &nslt); void SlObjectSaveFiltered(void *object, const SaveLoadTable &slt); void SlObjectLoadFiltered(void *object, const SaveLoadTable &slt); void SlObjectPtrOrNullFiltered(void *object, const SaveLoadTable &slt); From 9099caa059adb6a3da1113a1c867d26aab9d129b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 18:24:21 +0100 Subject: [PATCH 093/107] Saveload: Use table format for template vehicle chunks --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/tbtr_template_replacement_sl.cpp | 17 +++--- src/sl/tbtr_template_veh_sl.cpp | 79 +++++++++++++------------ src/tbtr_template_vehicle.h | 2 +- 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index e929780ae9..6e49bbc7ef 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -110,7 +110,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 6, 6, "linkgraph_day_scale", nullptr, nullptr, nullptr }, - { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 9, 9, "template_replacement", nullptr, nullptr, "TRPL,TMPL" }, + { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 10, 10, "template_replacement", nullptr, nullptr, "TRPL,TMPL" }, { XSLFI_MORE_RAIL_TYPES, XSCF_NULL, 0, 1, "more_rail_types", nullptr, nullptr, nullptr }, { XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 3, 3, "cargo_type_orders", nullptr, nullptr, "ORDX,VEOX" }, { XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 2, 2, "extended_gamelog", nullptr, nullptr, nullptr }, diff --git a/src/sl/tbtr_template_replacement_sl.cpp b/src/sl/tbtr_template_replacement_sl.cpp index d0f866aa23..0e49ac3177 100644 --- a/src/sl/tbtr_template_replacement_sl.cpp +++ b/src/sl/tbtr_template_replacement_sl.cpp @@ -4,32 +4,35 @@ #include "saveload.h" -static const SaveLoad _template_replacement_desc[] = { - SLE_VAR(TemplateReplacement, sel_template, SLE_UINT16), - SLE_VAR(TemplateReplacement, group, SLE_UINT16), +static const NamedSaveLoad _template_replacement_desc[] = { + NSL("sel_template", SLE_VAR(TemplateReplacement, sel_template, SLE_UINT16)), + NSL("group", SLE_VAR(TemplateReplacement, group, SLE_UINT16)), }; static void Save_TMPL_RPLS() { + SaveLoadTableData slt = SlTableHeader(_template_replacement_desc); + for (TemplateReplacement *tr : TemplateReplacement::Iterate()) { SlSetArrayIndex(tr->index); - SlObject(tr, _template_replacement_desc); + SlObjectSaveFiltered(tr, slt); } } static void Load_TMPL_RPLS() { - int index; + SaveLoadTableData slt = SlTableHeaderOrRiff(_template_replacement_desc); + int index; while ((index = SlIterateArray()) != -1) { TemplateReplacement *tr = new (index) TemplateReplacement(); - SlObject(tr, _template_replacement_desc); + SlObjectLoadFiltered(tr, slt); } ReindexTemplateReplacements(); } extern const ChunkHandler template_replacement_chunk_handlers[] = { - { 'TRPL', Save_TMPL_RPLS, Load_TMPL_RPLS, nullptr, nullptr, CH_ARRAY }, + { 'TRPL', Save_TMPL_RPLS, Load_TMPL_RPLS, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _template_replacement_chunk_handlers(template_replacement_chunk_handlers); diff --git a/src/sl/tbtr_template_veh_sl.cpp b/src/sl/tbtr_template_veh_sl.cpp index 2fbd92e369..669b774a6a 100644 --- a/src/sl/tbtr_template_veh_sl.cpp +++ b/src/sl/tbtr_template_veh_sl.cpp @@ -9,74 +9,79 @@ #include "saveload.h" -const SaveLoadTable GTD() { - static const SaveLoad _template_veh_desc[] = { - SLE_REF(TemplateVehicle, next, REF_TEMPLATE_VEHICLE), +NamedSaveLoadTable GetTemplateVehicleDesc() { + static const NamedSaveLoad _template_veh_desc[] = { + NSL("next", SLE_REF(TemplateVehicle, next, REF_TEMPLATE_VEHICLE)), - SLE_VAR(TemplateVehicle, reuse_depot_vehicles, SLE_UINT8), - SLE_VAR(TemplateVehicle, keep_remaining_vehicles, SLE_UINT8), - SLE_VAR(TemplateVehicle, refit_as_template, SLE_UINT8), - SLE_CONDVAR_X(TemplateVehicle, replace_old_only, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 5)), + NSL("reuse_depot_vehicles", SLE_VAR(TemplateVehicle, reuse_depot_vehicles, SLE_UINT8)), + NSL("keep_remaining_vehicles", SLE_VAR(TemplateVehicle, keep_remaining_vehicles, SLE_UINT8)), + NSL("refit_as_template", SLE_VAR(TemplateVehicle, refit_as_template, SLE_UINT8)), + NSL("replace_old_only", SLE_CONDVAR_X(TemplateVehicle, replace_old_only, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 5))), - SLE_CONDVAR_X(TemplateVehicle, owner, SLE_VAR_U8 | SLE_FILE_U32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)), - SLE_CONDVAR_X(TemplateVehicle, owner, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 4)), - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)), + NSL("owner", SLE_CONDVAR_X(TemplateVehicle, owner, SLE_VAR_U8 | SLE_FILE_U32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3))), + NSL("owner", SLE_CONDVAR_X(TemplateVehicle, owner, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 4))), + NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3))), - SLE_VAR(TemplateVehicle, engine_type, SLE_UINT16), - SLE_VAR(TemplateVehicle, cargo_type, SLE_UINT8), - SLE_VAR(TemplateVehicle, cargo_cap, SLE_UINT16), - SLE_VAR(TemplateVehicle, cargo_subtype, SLE_UINT8), + NSL("engine_type", SLE_VAR(TemplateVehicle, engine_type, SLE_UINT16)), + NSL("cargo_type", SLE_VAR(TemplateVehicle, cargo_type, SLE_UINT8)), + NSL("cargo_capacity", SLE_VAR(TemplateVehicle, cargo_cap, SLE_UINT16)), + NSL("cargo_subtype", SLE_VAR(TemplateVehicle, cargo_subtype, SLE_UINT8)), - SLE_VAR(TemplateVehicle, subtype, SLE_UINT8), - SLE_VAR(TemplateVehicle, railtype, SLE_UINT8), + NSL("subtype", SLE_VAR(TemplateVehicle, subtype, SLE_UINT8)), + NSL("railtype", SLE_VAR(TemplateVehicle, railtype, SLE_UINT8)), - SLE_VAR(TemplateVehicle, index, SLE_UINT32), + NSL("", SLE_VAR(TemplateVehicle, index, SLE_UINT32)), - SLE_VAR(TemplateVehicle, real_consist_length, SLE_UINT16), + NSL("real_consist_length", SLE_VAR(TemplateVehicle, real_consist_length, SLE_UINT16)), - SLE_VAR(TemplateVehicle, max_speed, SLE_UINT16), - SLE_VAR(TemplateVehicle, power, SLE_UINT32), - SLE_VAR(TemplateVehicle, empty_weight, SLE_UINT32), - SLE_CONDVAR_X(TemplateVehicle, full_weight, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 6)), - SLE_VAR(TemplateVehicle, max_te, SLE_UINT32), - SLE_CONDVAR_X(TemplateVehicle, air_drag, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 8)), + NSL("max_speed", SLE_VAR(TemplateVehicle, max_speed, SLE_UINT16)), + NSL("power", SLE_VAR(TemplateVehicle, power, SLE_UINT32)), + NSL("empty_weight", SLE_VAR(TemplateVehicle, empty_weight, SLE_UINT32)), + NSL("full_weight", SLE_CONDVAR_X(TemplateVehicle, full_weight, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 6))), + NSL("max_te", SLE_VAR(TemplateVehicle, max_te, SLE_UINT32)), + NSL("air_drag", SLE_CONDVAR_X(TemplateVehicle, air_drag, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 8))), - SLE_CONDVAR_X(TemplateVehicle, ctrl_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 7)), - SLE_CONDSSTR_X(TemplateVehicle, name, SLE_STR | SLF_ALLOW_CONTROL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 9)), + NSL("ctrl_flags", SLE_CONDVAR_X(TemplateVehicle, ctrl_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 7))), + NSL("name", SLE_CONDSSTR_X(TemplateVehicle, name, SLE_STR | SLF_ALLOW_CONTROL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 9))), - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 1)), - SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2, 3)), - SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3)), + NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3))), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 1))), + NSL("", SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2, 3))), + NSL("", SLE_CONDNULL_X(36, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 3))), }; return _template_veh_desc; -} +}; static void Save_TMPLS() { + SaveLoadTableData slt = SlTableHeader(GetTemplateVehicleDesc()); + for (TemplateVehicle *tv : TemplateVehicle::Iterate()) { SlSetArrayIndex(tv->index); - SlObject(tv, GTD()); + SlObjectSaveFiltered(tv, slt); } } static void Load_TMPLS() { - int index; + SaveLoadTableData slt = SlTableHeaderOrRiff(GetTemplateVehicleDesc()); + int index; while ((index = SlIterateArray()) != -1) { TemplateVehicle *tv = new (index) TemplateVehicle(); - SlObject(tv, GTD()); + SlObjectLoadFiltered(tv, slt); } } static void Ptrs_TMPLS() { + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetTemplateVehicleDesc()); + for (TemplateVehicle *tv : TemplateVehicle::Iterate()) { - SlObject(tv, GTD()); + SlObjectPtrOrNullFiltered(tv, slt); } } @@ -153,7 +158,7 @@ void AfterLoadTemplateVehiclesUpdateProperties() } extern const ChunkHandler template_vehicle_chunk_handlers[] = { - { 'TMPL', Save_TMPLS, Load_TMPLS, Ptrs_TMPLS, nullptr, CH_ARRAY }, + { 'TMPL', Save_TMPLS, Load_TMPLS, Ptrs_TMPLS, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _template_vehicle_chunk_handlers(template_vehicle_chunk_handlers); diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index e979ac3a60..aa6f333264 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -88,7 +88,7 @@ private: TemplateVehicle *first; ///< NOSAVE: pointer to the first vehicle in the chain public: - friend const SaveLoadTable GTD(); + friend NamedSaveLoadTable GetTemplateVehicleDesc(); friend void AfterLoadTemplateVehicles(); // Template usage configuration From fa69a975f39cff0ea8df5519476d01d4d79f3211 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 15 Jul 2024 18:49:26 +0100 Subject: [PATCH 094/107] Saveload: Use table format for towns chunk --- src/sl/extended_ver_sl.h | 2 +- src/sl/town_sl.cpp | 379 +++++++++++++++++++++++---------------- 2 files changed, 221 insertions(+), 160 deletions(-) diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index 346d480560..2772dacb9a 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -166,7 +166,7 @@ enum SlXvFeatureIndex { XSLFI_TABLE_MISC_SL, ///< Use upstream table format for miscellaneous chunks: ///< v1: DATE, VIEW, MAPS ///< v2: SUBS, CMDL, CMPU, ERNW, DEPT, CAPY, ECMY, EIDS, ENGN, GOAL, GRPS, RAIL, OBJS, SIGN, PSAC, STPE, STPA - ///< v3: CAPA + ///< v3: CAPA, CITY XSLFI_TABLE_SCRIPT_SL, ///< Use upstream table format for script chunks XSLFI_TABLE_NEWGRF_SL, ///< Use upstream table format for NewGRF/ID mapping chunks ///< In v1, NGRF chunks were saved incorrectly: see SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING diff --git a/src/sl/town_sl.cpp b/src/sl/town_sl.cpp index 008b4acd3f..65f82f7403 100644 --- a/src/sl/town_sl.cpp +++ b/src/sl/town_sl.cpp @@ -152,124 +152,18 @@ void UpdateHousesAndTowns(bool cargo_update_required, bool old_map_position) RebuildTownCaches(cargo_update_required, old_map_position); } -/** Save and load of towns. */ -static const SaveLoad _town_desc[] = { - SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Town, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_3), ///< population, no longer in use - SLE_CONDNULL(4, SLV_3, SLV_85), ///< population, no longer in use - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_92), ///< num_houses, no longer in use - - SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, SLV_66, SL_MAX_VERSION), - SLE_VAR(Town, townnametype, SLE_UINT16), - SLE_VAR(Town, townnameparts, SLE_UINT32), - SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION), - - SLE_VAR(Town, flags, SLE_UINT8), - SLE_CONDVAR_X(Town, church_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING)), - SLE_CONDVAR_X(Town, stadium_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING)), - SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), - SLE_CONDVAR(Town, statues, SLE_UINT16, SLV_104, SL_MAX_VERSION), - - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_2), ///< sort_index, no longer in use - - SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), - SLE_CONDVAR(Town, have_ratings, SLE_UINT16, SLV_104, SL_MAX_VERSION), - SLE_CONDARR(Town, ratings, SLE_INT16, 8, SL_MIN_VERSION, SLV_104), - SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), - SLE_CONDNULL_X(MAX_COMPANIES, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)), - /* failed bribe attempts are stored since savegame format 4 */ - SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104), - SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, SLV_104, SL_MAX_VERSION), - - SLE_CONDVAR(Town, supplied[0].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[2].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[0].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[2].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[0].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[2].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[0].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - SLE_CONDVAR(Town, supplied[2].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9), - - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[0].old_max, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[2].old_max, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[0].new_max, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[2].new_max, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[0].old_act, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[2].old_act, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[0].new_act, SLE_UINT32, SLV_9, SLV_165), - SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, supplied[2].new_act, SLE_UINT32, SLV_9, SLV_165), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), ///< pct_pass_transported / pct_mail_transported, now computed on the fly - SLE_CONDNULL_X(3, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - - SLE_CONDVAR(Town, received[TAE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), - SLE_CONDVAR(Town, received[TAE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), - SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, received[TAE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), - SLE_CONDVAR(Town, received[TAE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), - SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - - SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TAE, SLV_165, SL_MAX_VERSION), - - SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION), - - SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), - SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54), - SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, SL_MIN_VERSION, SLV_54), - - SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), - SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, SLV_54, SL_MAX_VERSION), - SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26)), - SLE_CONDVAR(Town, grow_counter, SLE_UINT16, SLV_54, SL_MAX_VERSION), - - SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, SLV_54, SLV_165), - SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26)), - SLE_CONDVAR(Town, growth_rate, SLE_UINT16, SLV_165, SL_MAX_VERSION), - - SLE_VAR(Town, fund_buildings_months, SLE_UINT8), - SLE_VAR(Town, road_build_months, SLE_UINT8), - - SLE_CONDVAR(Town, exclusivity, SLE_UINT8, SLV_2, SL_MAX_VERSION), - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, SLV_2, SL_MAX_VERSION), - - SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION), - SLE_CONDVAR(Town, layout, SLE_UINT8, SLV_113, SL_MAX_VERSION), - - SLE_CONDREFLIST(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION), - - SLE_CONDNULL(4, SLV_166, SLV_EXTEND_CARGOTYPES), ///< cargo_produced, no longer in use - SLE_CONDNULL(8, SLV_EXTEND_CARGOTYPES, SLV_REMOVE_TOWN_CARGO_CACHE), ///< cargo_produced, no longer in use - SLE_CONDNULL(30, SLV_2, SLV_REMOVE_TOWN_CARGO_CACHE), ///< old reserved space - - SLE_CONDVAR_X(Town, override_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)), - SLE_CONDVAR_X(Town, override_values, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)), - SLE_CONDVAR_X(Town, build_tunnels, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)), - SLE_CONDVAR_X(Town, max_road_slope, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE)), +static const NamedSaveLoad _town_supplied_desc[] = { + NSL("old_max", SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION)), + NSL("new_max", SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION)), + NSL("old_act", SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION)), + NSL("new_act", SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION)), }; -static const SaveLoad _town_supplied_desc[] = { - SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION), -}; - -static const SaveLoad _town_received_desc[] = { - SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), - SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION), +static const NamedSaveLoad _town_received_desc[] = { + NSL("old_max", SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT16, SLV_165, SL_MAX_VERSION)), + NSL("new_max", SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT16, SLV_165, SL_MAX_VERSION)), + NSL("old_act", SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT16, SLV_165, SL_MAX_VERSION)), + NSL("new_act", SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT16, SLV_165, SL_MAX_VERSION)), }; static const SaveLoad _town_received_desc_spp[] = { @@ -279,16 +173,184 @@ static const SaveLoad _town_received_desc_spp[] = { SLE_CONDVAR(TransportedCargoStat, new_act, SLE_FILE_U32 | SLE_VAR_U16, SLV_165, SL_MAX_VERSION), }; -std::vector _filtered_town_desc; -std::vector _filtered_town_supplied_desc; -std::vector _filtered_town_received_desc; +struct TownSuppliedStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _town_supplied_desc; + } -static void SetupDescs_TOWN() -{ - _filtered_town_desc = SlFilterObject(_town_desc); - _filtered_town_supplied_desc = SlFilterObject(_town_supplied_desc); - _filtered_town_received_desc = SlFilterObject(_town_received_desc); -} + void Save(Town *t) const override + { + SlSetStructListLength(std::size(t->supplied)); + for (auto &supplied : t->supplied) { + SlObjectSaveFiltered(&supplied, this->GetLoadDescription()); + } + } + + void Load(Town *t) const override + { + size_t count = SlGetStructListLength(std::size(t->supplied)); + for (size_t i = 0; i < count; i++) { + SlObjectLoadFiltered(&t->supplied[i], this->GetLoadDescription()); + } + } +}; + +struct TownReceivedStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _town_received_desc; + } + + void Save(Town *t) const override + { + SlSetStructListLength(std::size(t->received)); + for (auto &received : t->received) { + SlObjectSaveFiltered(&received, this->GetLoadDescription()); + } + } + + void Load(Town *t) const override + { + size_t count = SlGetStructListLength(std::size(t->received)); + for (size_t i = 0; i < count; i++) { + SlObjectLoadFiltered(&t->received[i], this->GetLoadDescription()); + } + } +}; + +struct TownSettingsOverrideStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + static const NamedSaveLoad _settings_override_desc[] = { + NSL("override_flags", SLE_VAR(Town, override_flags, SLE_UINT8)), + NSL("override_values", SLE_VAR(Town, override_values, SLE_UINT8)), + NSL("build_tunnels", SLE_VAR(Town, build_tunnels, SLE_UINT8)), + NSL("max_road_slope", SLE_VAR(Town, max_road_slope, SLE_UINT8)), + }; + return _settings_override_desc; + } + + void Save(Town *t) const override + { + SlObjectSaveFiltered(t, this->GetLoadDescription()); + } + + void Load(Town *t) const override + { + SlObjectLoadFiltered(t, this->GetLoadDescription()); + } +}; + +/** Save and load of towns. */ +static const NamedSaveLoad _town_desc[] = { + NSL("xy", SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6)), + NSL("xy", SLE_CONDVAR(Town, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION)), + + NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_3)), ///< population, no longer in use + NSL("", SLE_CONDNULL(4, SLV_3, SLV_85)), ///< population, no longer in use + NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_92)), ///< num_houses, no longer in use + + NSL("townnamegrfid", SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, SLV_66, SL_MAX_VERSION)), + NSL("townnametype", SLE_VAR(Town, townnametype, SLE_UINT16)), + NSL("townnameparts", SLE_VAR(Town, townnameparts, SLE_UINT32)), + NSL("name", SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, SLV_84, SL_MAX_VERSION)), + + NSL("flags", SLE_VAR(Town, flags, SLE_UINT8)), + NSL("church_count", SLE_CONDVAR_X(Town, church_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING))), + NSL("stadium_count", SLE_CONDVAR_X(Town, stadium_count, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_MULTI_BUILDING))), + NSL("statues", SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104)), + NSL("statues", SLE_CONDVAR(Town, statues, SLE_UINT16, SLV_104, SL_MAX_VERSION)), + + NSL("", SLE_CONDNULL(1, SL_MIN_VERSION, SLV_2)), ///< sort_index, no longer in use + + NSL("have_ratings", SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104)), + NSL("have_ratings", SLE_CONDVAR(Town, have_ratings, SLE_UINT16, SLV_104, SL_MAX_VERSION)), + NSL("ratings", SLE_CONDARR(Town, ratings, SLE_INT16, 8, SL_MIN_VERSION, SLV_104)), + NSL("ratings", SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, SLV_104, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL_X(MAX_COMPANIES, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP))), + /* failed bribe attempts are stored since savegame format 4 */ + NSL("unwanted", SLE_CONDARR(Town, unwanted, SLE_INT8, 8, SLV_4, SLV_104)), + NSL("unwanted", SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, SLV_104, SL_MAX_VERSION)), + + NSL("", SLE_CONDVAR(Town, supplied[0].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[2].old_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[0].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[2].new_max, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[0].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[2].old_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[0].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + NSL("", SLE_CONDVAR(Town, supplied[2].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9)), + + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_PASSENGERS].old_max", SLE_CONDVAR(Town, supplied[0].old_max, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_MAIL].old_max", SLE_CONDVAR(Town, supplied[2].old_max, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_PASSENGERS].new_max", SLE_CONDVAR(Town, supplied[0].new_max, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_MAIL].new_max", SLE_CONDVAR(Town, supplied[2].new_max, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_PASSENGERS].old_act", SLE_CONDVAR(Town, supplied[0].old_act, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_MAIL].old_act", SLE_CONDVAR(Town, supplied[2].old_act, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_PASSENGERS].new_act", SLE_CONDVAR(Town, supplied[0].new_act, SLE_UINT32, SLV_9, SLV_165)), + NSL("", SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("supplied[CT_MAIL].new_act", SLE_CONDVAR(Town, supplied[2].new_act, SLE_UINT32, SLV_9, SLV_165)), + + NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164)), ///< pct_pass_transported / pct_mail_transported, now computed on the fly + NSL("", SLE_CONDNULL_X(3, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + + NSL("received[TE_FOOD].old_act", SLE_CONDVAR(Town, received[TAE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165)), + NSL("received[TAE_WATER].old_act", SLE_CONDVAR(Town, received[TAE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165)), + NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("received[TE_FOOD].new_act", SLE_CONDVAR(Town, received[TAE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165)), + NSL("received[TE_WATER].new_act", SLE_CONDVAR(Town, received[TAE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165)), + NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + + NSL("goal", SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TAE, SLV_165, SL_MAX_VERSION)), + + NSL("text", SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION)), + + NSL("time_until_rebuild", SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54)), + NSL("grow_counter", SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_54)), + NSL("growth_rate", SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, SL_MIN_VERSION, SLV_54)), + + NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))), + NSL("time_until_rebuild", SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, SLV_54, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26))), + NSL("grow_counter", SLE_CONDVAR(Town, grow_counter, SLE_UINT16, SLV_54, SL_MAX_VERSION)), + + NSL("growth_rate", SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, SLV_54, SLV_165)), + NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP, SL_JOKER_1_26))), + NSL("growth_rate", SLE_CONDVAR(Town, growth_rate, SLE_UINT16, SLV_165, SL_MAX_VERSION)), + + NSL("fund_buildings_months", SLE_VAR(Town, fund_buildings_months, SLE_UINT8)), + NSL("road_build_months", SLE_VAR(Town, road_build_months, SLE_UINT8)), + + NSL("exclusivity", SLE_CONDVAR(Town, exclusivity, SLE_UINT8, SLV_2, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232))), + NSL("exclusive_counter", SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, SLV_2, SL_MAX_VERSION)), + + NSL("larger_town", SLE_CONDVAR(Town, larger_town, SLE_BOOL, SLV_56, SL_MAX_VERSION)), + NSL("layout", SLE_CONDVAR(Town, layout, SLE_UINT8, SLV_113, SL_MAX_VERSION)), + + NSL("psa_list", SLE_CONDREFLIST(Town, psa_list, REF_STORAGE, SLV_161, SL_MAX_VERSION)), + + NSL("", SLE_CONDNULL(4, SLV_166, SLV_EXTEND_CARGOTYPES)), ///< cargo_produced, no longer in use + NSL("", SLE_CONDNULL(8, SLV_EXTEND_CARGOTYPES, SLV_REMOVE_TOWN_CARGO_CACHE)), ///< cargo_produced, no longer in use + NSL("", SLE_CONDNULL(30, SLV_2, SLV_REMOVE_TOWN_CARGO_CACHE)), ///< old reserved space + + NSL("", SLE_CONDVAR_X(Town, override_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE))), + NSL("", SLE_CONDVAR_X(Town, override_values, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE))), + NSL("", SLE_CONDVAR_X(Town, build_tunnels, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE))), + NSL("", SLE_CONDVAR_X(Town, max_road_slope, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TOWN_SETTING_OVERRIDE))), + + NSLT_STRUCTLIST("supplied"), + NSLT_STRUCTLIST("received"), + NSLT_STRUCT("setting_overrides"), +}; static void Save_HIDS() { @@ -300,54 +362,52 @@ static void Load_HIDS() Load_NewGRFMapping(_house_mngr); } -static void RealSave_Town(Town *t) -{ - SlObjectSaveFiltered(t, _filtered_town_desc); - - for (CargoID i = 0; i < NUM_CARGO; i++) { - SlObjectSaveFiltered(&t->supplied[i], _filtered_town_supplied_desc); - } - for (int i = TAE_BEGIN; i < NUM_TAE; i++) { - SlObjectSaveFiltered(&t->received[i], _filtered_town_received_desc); - } -} - static void Save_TOWN() { - SetupDescs_TOWN(); + SaveLoadTableData slt = SlTableHeader(_town_desc); + for (Town *t : Town::Iterate()) { SlSetArrayIndex(t->index); - SlAutolength(RealSave_Town, t); + SlObjectSaveFiltered(t, slt); } } static void Load_TOWN() { - SetupDescs_TOWN(); - int index; - uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + SaveLoadTableData slt = SlTableHeaderOrRiff(_town_desc); + std::vector supplied_desc; + std::vector received_desc; + if (!SlIsTableChunk()) { + supplied_desc = SlFilterNamedSaveLoadTable(_town_supplied_desc); + if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { + received_desc = SlFilterObject(_town_received_desc_spp); + } else { + received_desc = SlFilterNamedSaveLoadTable(_town_received_desc); + } + } + + uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; + static_assert(static_cast(TAE_BEGIN) == 0 && static_cast(NUM_TAE) == 6); + + int index; while ((index = SlIterateArray()) != -1) { Town *t = new (index) Town(); - SlObjectLoadFiltered(t, _filtered_town_desc); - - for (CargoID i = 0; i < num_cargo; i++) { - SlObjectLoadFiltered(&t->supplied[i], _filtered_town_supplied_desc); - } - if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { - for (int i = TAE_BEGIN; i < NUM_TAE; i++) { - SlObject(&t->received[i], _town_received_desc_spp); - } - } else { - for (int i = TAE_BEGIN; i < NUM_TAE; i++) { - SlObjectLoadFiltered(&t->received[i], _filtered_town_received_desc); - } - } + SlObjectLoadFiltered(t, slt); if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) { SlErrorCorrupt("Invalid town name generator"); } + if (SlIsTableChunk()) continue; + + for (CargoID i = 0; i < num_cargo; i++) { + SlObjectLoadFiltered(&t->supplied[i], supplied_desc); + } + for (int i = TAE_BEGIN; i < NUM_TAE; i++) { + SlObjectLoadFiltered(&t->received[i], received_desc); + } + if ((!IsSavegameVersionBefore(SLV_166) && IsSavegameVersionBefore(SLV_REMOVE_TOWN_CARGO_CACHE)) || SlXvIsFeaturePresent(XSLFI_TOWN_CARGO_MATRIX)) { SlSkipBytes(4); // tile uint16_t w = SlReadUint16(); @@ -365,9 +425,10 @@ static void Ptrs_TOWN() /* Don't run when savegame version lower than 161. */ if (IsSavegameVersionBefore(SLV_161)) return; - SetupDescs_TOWN(); + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(_town_desc); + for (Town *t : Town::Iterate()) { - SlObjectPtrOrNullFiltered(t, _filtered_town_desc); + SlObjectPtrOrNullFiltered(t, slt); } } @@ -455,7 +516,7 @@ static ChunkSaveLoadSpecialOpResult Special_TNNC(uint32_t chunk_id, ChunkSaveLoa /** Chunk handler for towns. */ static const ChunkHandler town_chunk_handlers[] = { { 'HIDS', Save_HIDS, Load_HIDS, nullptr, nullptr, CH_TABLE }, - { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, nullptr, CH_ARRAY }, + { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, nullptr, CH_TABLE }, { 'TNNC', Save_TNNC, Load_TNNC, nullptr, nullptr, CH_RIFF, Special_TNNC }, }; From a24a39a6afe24bee5252c4540878ec3df8fe5041 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 17:45:27 +0100 Subject: [PATCH 095/107] Saveload: Tag functions returning SaveLoadTableData with [[nodiscard]] --- src/sl/saveload.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sl/saveload.h b/src/sl/saveload.h index da75c34c7a..4643d24390 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1093,9 +1093,9 @@ struct TableHeaderSpecialHandler { bool SlIsTableChunk(); void SlSkipTableHeader(); -SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); -SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); -SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTable &slt); +[[nodiscard]] SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); +[[nodiscard]] SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); +[[nodiscard]] SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTable &slt); void SlSaveTableObjectChunk(const SaveLoadTable &slt); void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); void SlLoadTableWithArrayLengthPrefixesMissing(); From 34177c70aab00b847d8861e1a802225cf8e5fc67 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 17:59:34 +0100 Subject: [PATCH 096/107] Saveload: Simplify load of (vanilla) company settings --- src/sl/company_sl.cpp | 53 ++++++++++++------------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index 34023f5ec8..2e9114f50d 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -311,40 +311,19 @@ static const SaveLoad _company_desc[] = { static const SaveLoad _company_settings_desc[] = { /* Engine renewal settings */ SLE_CONDNULL(512, SLV_16, SLV_19), - SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION), + SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION), /* Default vehicle settings */ - SLE_CONDVAR(Company, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(Company, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR_X(Company, settings.vehicle.auto_timetable_by_default, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), - - SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space -}; - -static const SaveLoad _company_settings_skip_desc[] = { - /* Engine renewal settings */ - SLE_CONDNULL(512, SLV_16, SLV_19), - SLE_CONDNULL(2, SLV_19, SLV_69), // engine_renew_list - SLE_CONDNULL(4, SLV_69, SL_MAX_VERSION), // engine_renew_list - SLE_CONDNULL(1, SLV_16, SL_MAX_VERSION), // settings.engine_renew - SLE_CONDNULL(2, SLV_16, SL_MAX_VERSION), // settings.engine_renew_months - SLE_CONDNULL(4, SLV_16, SL_MAX_VERSION), // settings.engine_renew_money - SLE_CONDNULL(1, SLV_2, SL_MAX_VERSION), // settings.renew_keep_length - - /* Default vehicle settings */ - SLE_CONDNULL(1, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ispercent - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_trains - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_roadveh - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_aircraft - SLE_CONDNULL(2, SLV_120, SL_MAX_VERSION), // settings.vehicle.servint_ships - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), // settings.vehicle.auto_timetable_by_default + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION), + SLE_CONDVAR_X(CompanyProperties, settings.vehicle.auto_timetable_by_default, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space }; @@ -418,12 +397,7 @@ static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) int i; SlObject(cprops, _company_desc); - if (c != nullptr) { - SlObject(c, _company_settings_desc); - } else { - char nothing; - SlObject(¬hing, _company_settings_skip_desc); - } + SlObject(cprops, _company_settings_desc); /* Keep backwards compatible for savegames, so load the old AI block */ if (IsSavegameVersionBefore(SLV_107) && cprops->is_ai) { @@ -548,7 +522,8 @@ static void Check_PLYR() static void Ptrs_PLYR() { for (Company *c : Company::Iterate()) { - SlObject(c, _company_settings_desc); + CompanyProperties *cprops = c; + SlObject(cprops, _company_settings_desc); } } From c2e7c67204bd5dd719cd26a850c1632742ae884d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 18:58:15 +0100 Subject: [PATCH 097/107] Saveload: Use table format for companies chunk --- src/settings.cpp | 77 +------ src/sl/company_sl.cpp | 451 +++++++++++++++++++++++++------------ src/sl/extended_ver_sl.cpp | 1 + src/sl/extended_ver_sl.h | 1 + 4 files changed, 311 insertions(+), 219 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 5b9667446b..ab83152592 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3705,21 +3705,6 @@ static const SaveLoad _settings_ext_load_desc[] = { SLE_VAR(SettingsExtLoad, setting_length, SLE_UINT32), }; -/** - * Internal structure used in SaveSettingsPlyx() - */ -struct SettingsExtSave { - uint32_t flags; - const char *name; - uint32_t setting_length; -}; - -static const SaveLoad _settings_ext_save_desc[] = { - SLE_VAR(SettingsExtSave, flags, SLE_UINT32), - SLE_STR(SettingsExtSave, name, SLE_STR, 0), - SLE_VAR(SettingsExtSave, setting_length, SLE_UINT32), -}; - /** * Load handler for settings which go in the PATX chunk * @param object can be either nullptr in which case we load global variables or @@ -3865,65 +3850,17 @@ void LoadSettingsPlyx(bool skip) } } -/** - * Save handler for settings which go in the PLYX chunk - */ -void SaveSettingsPlyx() +std::vector FillPlyrExtraSettingsDesc() { - SettingsExtSave current_setting; + std::vector settings_desc; - std::vector company_setting_counts; - - size_t length = 8; - uint32_t companies_count = 0; - - for (Company *c : Company::Iterate()) { - length += 12; - companies_count++; - uint32_t setting_count = 0; - for (auto &sd : _company_settings) { - if (sd->patx_name == nullptr) continue; - uint32_t setting_length = (uint32_t)SlCalcObjMemberLength(&(c->settings), sd->save); - if (!setting_length) continue; - - current_setting.name = sd->patx_name; - - // add length of setting header - length += SlCalcObjLength(¤t_setting, _settings_ext_save_desc); - - // add length of actual setting - length += setting_length; - - setting_count++; - } - company_setting_counts.push_back(setting_count); - } - SlSetLength(length); - - SlWriteUint32(0); // flags - SlWriteUint32(companies_count); // companies count - - size_t index = 0; - for (Company *c : Company::Iterate()) { - length += 12; - companies_count++; - SlWriteUint32(c->index); // company ID - SlWriteUint32(0); // flags - SlWriteUint32(company_setting_counts[index]); // setting count - index++; - - for (auto &sd : _company_settings) { - if (sd->patx_name == nullptr) continue; - uint32_t setting_length = (uint32_t)SlCalcObjMemberLength(&(c->settings), sd->save); - if (!setting_length) continue; - - current_setting.flags = 0; - current_setting.name = sd->patx_name; - current_setting.setting_length = setting_length; - SlObject(¤t_setting, _settings_ext_save_desc); - SlObjectMember(&(c->settings), sd->save); + for (auto &sd : _company_settings) { + if (sd->patx_name != nullptr) { + settings_desc.push_back(NSL(sd->patx_name, sd->save)); } } + + return settings_desc; } static void Load_OPTS() diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index 2e9114f50d..e86aed67ed 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -242,105 +242,39 @@ void AfterLoadCompanyStats() } } - - -/* Save/load of companies */ -static const SaveLoad _company_desc[] = { - SLE_VAR(CompanyProperties, name_2, SLE_UINT32), - SLE_VAR(CompanyProperties, name_1, SLE_STRINGID), - SLE_CONDSSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), - - SLE_VAR(CompanyProperties, president_name_1, SLE_STRINGID), - SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32), - SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION), - - SLE_VAR(CompanyProperties, face, SLE_UINT32), - - /* money was changed to a 64 bit field in savegame version 1. */ - SLE_CONDVAR(CompanyProperties, money, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_1), - SLE_CONDVAR(CompanyProperties, money, SLE_INT64, SLV_1, SL_MAX_VERSION), - - SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65), - SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION), - - SLE_VAR(CompanyProperties, colour, SLE_UINT8), - SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8), - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_58), ///< avail_railtypes - SLE_VAR(CompanyProperties, block_preview, SLE_UINT8), - - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_94), ///< cargo_types - SLE_CONDNULL(4, SLV_94, SLV_170), ///< cargo_types - SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_CONDVAR_X(CompanyProperties, display_inaugurated_period, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6)), - SLE_CONDVAR_X(CompanyProperties, age_years, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6)), - - SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4), - - SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8), - - SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), - SLE_CONDVAR_X(CompanyProperties, bankrupt_last_asked, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA)), - SLE_CONDVAR_X(CompanyProperties, bankrupt_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA, 2)), - SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), - SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION), - SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16), - SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65), - SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION), - - /* yearly expenses was changed to 64-bit in savegame version 2. */ - SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2), - SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING, 0, 0)), - SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 15, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING)), - - SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, SLV_2, SL_MAX_VERSION), - SLE_CONDNULL(1, SLV_107, SLV_112), ///< is_noai - SLE_CONDNULL(1, SLV_4, SLV_100), - - SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, SLV_175, SL_MAX_VERSION), - SLE_CONDVAR_X(CompanyProperties, purchase_land_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUY_LAND_RATE_LIMIT)), - SLE_CONDVAR_X(CompanyProperties, build_object_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUILD_OBJECT_RATE_LIMIT)), -}; - -static const SaveLoad _company_settings_desc[] = { +static const NamedSaveLoad _company_settings_desc[] = { /* Engine renewal settings */ - SLE_CONDNULL(512, SLV_16, SLV_19), - SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION), + NSL("", SLE_CONDNULL(512, SLV_16, SLV_19)), + NSL("engine_renew_list", SLE_CONDREF(CompanyProperties, engine_renew_list, REF_ENGINE_RENEWS, SLV_19, SL_MAX_VERSION)), + NSL("settings.engine_renew", SLE_CONDVAR(CompanyProperties, settings.engine_renew, SLE_BOOL, SLV_16, SL_MAX_VERSION)), + NSL("settings.engine_renew_months", SLE_CONDVAR(CompanyProperties, settings.engine_renew_months, SLE_INT16, SLV_16, SL_MAX_VERSION)), + NSL("settings.engine_renew_money", SLE_CONDVAR(CompanyProperties, settings.engine_renew_money, SLE_UINT32, SLV_16, SL_MAX_VERSION)), + NSL("settings.renew_keep_length", SLE_CONDVAR(CompanyProperties, settings.renew_keep_length, SLE_BOOL, SLV_2, SL_MAX_VERSION)), /* Default vehicle settings */ - SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION), - SLE_CONDVAR_X(CompanyProperties, settings.vehicle.auto_timetable_by_default, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2)), + NSL("settings.vehicle.servint_ispercent", SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ispercent, SLE_BOOL, SLV_120, SL_MAX_VERSION)), + NSL("settings.vehicle.servint_trains", SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_trains, SLE_UINT16, SLV_120, SL_MAX_VERSION)), + NSL("settings.vehicle.servint_roadveh", SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_roadveh, SLE_UINT16, SLV_120, SL_MAX_VERSION)), + NSL("settings.vehicle.servint_aircraft", SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_aircraft, SLE_UINT16, SLV_120, SL_MAX_VERSION)), + NSL("settings.vehicle.servint_ships", SLE_CONDVAR(CompanyProperties, settings.vehicle.servint_ships, SLE_UINT16, SLV_120, SL_MAX_VERSION)), + NSL("settings.vehicle.auto_timetable_by_default", SLE_CONDVAR_X(CompanyProperties, settings.vehicle.auto_timetable_by_default, SLE_BOOL, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUTO_TIMETABLE, 2, 2))), - SLE_CONDNULL(63, SLV_2, SLV_144), // old reserved space + NSL("", SLE_CONDNULL(63, SLV_2, SLV_144)), // old reserved space }; -static const SaveLoad _company_economy_desc[] = { +static const NamedSaveLoad _company_economy_desc[] = { /* these were changed to 64-bit in savegame format 2 */ - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2), - SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION), + NSL("income", SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2)), + NSL("income", SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, SLV_2, SL_MAX_VERSION)), + NSL("expenses", SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2)), + NSL("expenses", SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, SLV_2, SL_MAX_VERSION)), + NSL("company_value", SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SLV_2)), + NSL("company_value", SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, SLV_2, SL_MAX_VERSION)), - SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170), - SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES), - SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), - SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), + NSL("", SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, SL_MIN_VERSION, SLV_170)), + NSL("delivered_cargo", SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, 32, SLV_170, SLV_EXTEND_CARGOTYPES)), + NSL("delivered_cargo", SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION)), + NSL("performance_history", SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32)), }; /* We do need to read this single value, as the bigger it gets, the more data is stored */ @@ -386,18 +320,249 @@ static const SaveLoad _company_ai_build_rec_desc[] = { SLE_CONDNULL(8, SL_MIN_VERSION, SLV_107), }; -static const SaveLoad _company_livery_desc[] = { - SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION), - SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION), +static const NamedSaveLoad _company_livery_desc[] = { + NSL("in_use", SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION)), + NSL("colour1", SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION)), + NSL("colour2", SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION)), }; -static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) +static void LoadLiveries(CompanyProperties *c, uint num_liveries, const SaveLoadTable &slt) { - int i; + bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); - SlObject(cprops, _company_desc); - SlObject(cprops, _company_settings_desc); + for (uint i = 0; i < num_liveries; i++) { + SlObjectLoadFiltered(&c->livery[i], slt); + if (update_in_use && i != LS_DEFAULT) { + if (c->livery[i].in_use == 0) { + c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1; + c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2; + } else { + c->livery[i].in_use = 3; + } + } + } + + if (num_liveries < LS_END) { + /* We want to insert some liveries somewhere in between. This means some have to be moved. */ + memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); + c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; + c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; + } + + if (num_liveries == LS_END - 4) { + /* Copy bus/truck liveries over to trams */ + c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; + c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; + } +} + +struct CompanySettingsStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _company_settings_desc; + } + + void Save(CompanyProperties *cprops) const override + { + SlObjectSaveFiltered(cprops, this->GetLoadDescription()); + } + + void Load(CompanyProperties *cprops) const override + { + SlObjectLoadFiltered(cprops, this->GetLoadDescription()); + } + + void LoadCheck(CompanyProperties *cprops) const override { this->Load(cprops); } + + void FixPointers(CompanyProperties *cprops) const override + { + SlObjectPtrOrNullFiltered(cprops, this->GetLoadDescription()); + } +}; + +struct CompanyExtraSettingsStructHandler final : public TypedSaveLoadStructHandler { + std::vector settings_desc; + + CompanyExtraSettingsStructHandler() + { + extern std::vector FillPlyrExtraSettingsDesc(); + this->settings_desc = FillPlyrExtraSettingsDesc(); + } + + NamedSaveLoadTable GetDescription() const override + { + return this->settings_desc; + } + + void Save(CompanyProperties *cprops) const override + { + SlObjectSaveFiltered(&(cprops->settings), this->GetLoadDescription()); + } + + void Load(CompanyProperties *cprops) const override + { + SlObjectLoadFiltered(&(cprops->settings), this->GetLoadDescription()); + } + + void LoadCheck(CompanyProperties *cprops) const override { this->Load(cprops); } +}; + +struct CompanyCurEconomyStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _company_economy_desc; + } + + void Save(CompanyProperties *cprops) const override + { + SlObjectSaveFiltered(&cprops->cur_economy, this->GetLoadDescription()); + } + + void Load(CompanyProperties *cprops) const override + { + SlObjectLoadFiltered(&cprops->cur_economy, this->GetLoadDescription()); + } + + void LoadCheck(CompanyProperties *cprops) const override { this->Load(cprops); } +}; + +struct CompanyOldEconomyStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _company_economy_desc; + } + + void Save(CompanyProperties *cprops) const override + { + SlSetStructListLength(cprops->num_valid_stat_ent); + for (int i = 0; i < cprops->num_valid_stat_ent; i++) { + SlObjectSaveFiltered(&cprops->old_economy[i], this->GetLoadDescription()); + } + } + + void Load(CompanyProperties *cprops) const override + { + cprops->num_valid_stat_ent = static_cast(SlGetStructListLength(lengthof(cprops->old_economy))); + + for (int i = 0; i < cprops->num_valid_stat_ent; i++) { + SlObjectLoadFiltered(&cprops->old_economy[i], this->GetLoadDescription()); + } + } + + void LoadCheck(CompanyProperties *cprops) const override { this->Load(cprops); } +}; + +struct CompanyLiveriesStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return _company_livery_desc; + } + + void Save(CompanyProperties *cprops) const override + { + SlSetStructListLength(LS_END); + for (int i = 0; i < LS_END; i++) { + SlObjectSaveFiltered(&cprops->livery[i], this->GetLoadDescription()); + } + } + + void Load(CompanyProperties *cprops) const override + { + uint num_liveries = static_cast(SlGetStructListLength(LS_END)); + LoadLiveries(cprops, num_liveries, this->GetLoadDescription()); + } + + void LoadCheck(CompanyProperties *cprops) const override { this->Load(cprops); } +}; + +/* Save/load of companies */ +static const NamedSaveLoad _company_desc[] = { + NSL("name_2", SLE_VAR(CompanyProperties, name_2, SLE_UINT32)), + NSL("name_1", SLE_VAR(CompanyProperties, name_1, SLE_STRINGID)), + NSL("name", SLE_CONDSSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION)), + + NSL("president_name_1", SLE_VAR(CompanyProperties, president_name_1, SLE_STRINGID)), + NSL("president_name_2", SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32)), + NSL("president_name", SLE_CONDSSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, SLV_84, SL_MAX_VERSION)), + + NSL("face", SLE_VAR(CompanyProperties, face, SLE_UINT32)), + + /* money was changed to a 64 bit field in savegame version 1. */ + NSL("money", SLE_CONDVAR(CompanyProperties, money, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_1)), + NSL("money", SLE_CONDVAR(CompanyProperties, money, SLE_INT64, SLV_1, SL_MAX_VERSION)), + + NSL("current_loan", SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65)), + NSL("current_loan", SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION)), + + NSL("colour", SLE_VAR(CompanyProperties, colour, SLE_UINT8)), + NSL("money_fraction", SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8)), + NSL("", SLE_CONDNULL(1, SL_MIN_VERSION, SLV_58)), ///< avail_railtypes + NSL("block_preview", SLE_VAR(CompanyProperties, block_preview, SLE_UINT8)), + + NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_94)), ///< cargo_types + NSL("", SLE_CONDNULL(4, SLV_94, SLV_170)), ///< cargo_types + NSL("location_of_HQ", SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6)), + NSL("location_of_HQ", SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, SLV_6, SL_MAX_VERSION)), + NSL("last_build_coordinate", SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6)), + NSL("last_build_coordinate", SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, SLV_6, SL_MAX_VERSION)), + NSL("inaugurated_year", SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31)), + NSL("inaugurated_year", SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, SLV_31, SL_MAX_VERSION)), + NSL("display_inaugurated_period", SLE_CONDVAR_X(CompanyProperties, display_inaugurated_period, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6))), + NSL("age_years", SLE_CONDVAR_X(CompanyProperties, age_years, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VARIABLE_DAY_LENGTH, 6))), + + NSL("share_owners", SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4)), + + NSL("", SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8)), // Not required in table format + + NSL("months_of_bankruptcy", SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8)), + NSL("bankrupt_last_asked", SLE_CONDVAR_X(CompanyProperties, bankrupt_last_asked, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA))), + NSL("bankrupt_flags", SLE_CONDVAR_X(CompanyProperties, bankrupt_flags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA, 2))), + NSL("bankrupt_asked", SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104)), + NSL("bankrupt_asked", SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION)), + NSL("bankrupt_timeout", SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16)), + NSL("bankrupt_value", SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65)), + NSL("bankrupt_value", SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, SLV_65, SL_MAX_VERSION)), + + /* yearly expenses was changed to 64-bit in savegame version 2. */ + NSL("yearly_expenses", SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, SL_MIN_VERSION, SLV_2)), + NSL("yearly_expenses", SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING, 0, 0))), + NSL("yearly_expenses", SLE_CONDARR_X(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 15, SLV_2, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INFRA_SHARING))), + + NSL("is_ai", SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, SLV_2, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL(1, SLV_107, SLV_112)), ///< is_noai + NSL("", SLE_CONDNULL(1, SLV_4, SLV_100)), + + NSL("terraform_limit", SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION)), + NSL("clear_limit", SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, SLV_156, SL_MAX_VERSION)), + NSL("tree_limit", SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, SLV_175, SL_MAX_VERSION)), + NSL("purchase_land_limit", SLE_CONDVAR_X(CompanyProperties, purchase_land_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUY_LAND_RATE_LIMIT))), + NSL("build_object_limit", SLE_CONDVAR_X(CompanyProperties, build_object_limit, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BUILD_OBJECT_RATE_LIMIT))), + + NSLT_STRUCT("settings"), + NSLT_STRUCT("extra_settings"), + NSLT_STRUCT("cur_economy"), + NSLT_STRUCTLIST("old_economy"), + NSLT_STRUCTLIST("liveries"), +}; + +struct PLYRNonTableHelper { + std::vector liveries_desc; + std::vector economy_desc; + std::vector settings_desc; + + void Setup() + { + this->liveries_desc = SlFilterNamedSaveLoadTable(_company_livery_desc); + this->economy_desc = SlFilterNamedSaveLoadTable(_company_economy_desc); + this->settings_desc = SlFilterNamedSaveLoadTable(_company_settings_desc); + } + + void Load_PLYR_common(Company *c, CompanyProperties *cprops); +}; + +void PLYRNonTableHelper::Load_PLYR_common(Company *c, CompanyProperties *cprops) +{ + SlObjectLoadFiltered(cprops, settings_desc); /* Keep backwards compatible for savegames, so load the old AI block */ if (IsSavegameVersionBefore(SLV_107) && cprops->is_ai) { @@ -405,80 +570,64 @@ static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) char nothing; SlObject(&old_ai, _company_ai_desc); - for (i = 0; i != old_ai.num_build_rec; i++) { + for (uint i = 0; i != old_ai.num_build_rec; i++) { SlObject(¬hing, _company_ai_build_rec_desc); } } /* Write economy */ - SlObject(&cprops->cur_economy, _company_economy_desc); + SlObjectLoadFiltered(&cprops->cur_economy, this->economy_desc); /* Write old economy entries. */ if (cprops->num_valid_stat_ent > lengthof(cprops->old_economy)) SlErrorCorrupt("Too many old economy entries"); - for (i = 0; i < cprops->num_valid_stat_ent; i++) { - SlObject(&cprops->old_economy[i], _company_economy_desc); + for (uint i = 0; i < cprops->num_valid_stat_ent; i++) { + SlObjectLoadFiltered(&cprops->old_economy[i], this->economy_desc); } /* Write each livery entry. */ - int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END); - bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); + uint num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END); + if (c != nullptr) { - for (i = 0; i < num_liveries; i++) { - SlObject(&c->livery[i], _company_livery_desc); - if (update_in_use && i != LS_DEFAULT) { - if (c->livery[i].in_use == 0) { - c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1; - c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2; - } else { - c->livery[i].in_use = 3; - } - } - } - - if (num_liveries < LS_END) { - /* We want to insert some liveries somewhere in between. This means some have to be moved. */ - memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); - c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; - c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; - } - - if (num_liveries == LS_END - 4) { - /* Copy bus/truck liveries over to trams */ - c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; - c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; - } + LoadLiveries(cprops, num_liveries, this->liveries_desc); } else { /* Skip liveries */ Livery dummy_livery; - for (i = 0; i < num_liveries; i++) { - SlObject(&dummy_livery, _company_livery_desc); + for (uint i = 0; i < num_liveries; i++) { + SlObjectLoadFiltered(&dummy_livery, this->liveries_desc); } } } -static void SaveLoad_PLYR(Company *c) -{ - SaveLoad_PLYR_common(c, c); -} - static void Save_PLYR() { + SaveLoadTableData slt = SlTableHeader(_company_desc); + for (Company *c : Company::Iterate()) { + CompanyProperties *cprops = c; SlSetArrayIndex(c->index); - SlAutolength(SaveLoad_PLYR, c); + SlObjectSaveFiltered(cprops, slt); } } static void Load_PLYR() { + SaveLoadTableData slt = SlTableHeaderOrRiff(_company_desc); + + PLYRNonTableHelper helper; + if (!SlIsTableChunk()) helper.Setup(); + int index; while ((index = SlIterateArray()) != -1) { Company *c = new (index) Company(); + CompanyProperties *cprops = c; SetDefaultCompanySettings(c->index); - SaveLoad_PLYR(c); + SlObjectLoadFiltered(cprops, slt); + if (!SlIsTableChunk()) { + helper.Load_PLYR_common(c, cprops); + } _company_colours[index] = (Colours)c->colour; - // settings moved from game settings to company settings + /* settings moved from game settings to company settings */ if (SlXvIsFeaturePresent(XSLFI_AUTO_TIMETABLE, 1, 2)) { c->settings.auto_timetable_separation_rate = _settings_game.order.old_timetable_separation_rate; } @@ -490,10 +639,18 @@ static void Load_PLYR() static void Check_PLYR() { + SaveLoadTableData slt = SlTableHeaderOrRiff(_company_desc); + + PLYRNonTableHelper helper; + if (!SlIsTableChunk()) helper.Setup(); + int index; while ((index = SlIterateArray()) != -1) { std::unique_ptr cprops = std::make_unique(); - SaveLoad_PLYR_common(nullptr, cprops.get()); + SlObjectLoadFiltered(cprops.get(), slt); + if (!SlIsTableChunk()) { + helper.Load_PLYR_common(nullptr, cprops.get()); + } /* We do not load old custom names */ if (IsSavegameVersionBefore(SLV_84)) { @@ -521,14 +678,15 @@ static void Check_PLYR() static void Ptrs_PLYR() { + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(_company_settings_desc); + for (Company *c : Company::Iterate()) { CompanyProperties *cprops = c; - SlObject(cprops, _company_settings_desc); + SlObjectPtrOrNullFiltered(cprops, slt); } } extern void LoadSettingsPlyx(bool skip); -extern void SaveSettingsPlyx(); static void Load_PLYX() { @@ -540,11 +698,6 @@ static void Check_PLYX() LoadSettingsPlyx(true); } -static void Save_PLYX() -{ - SaveSettingsPlyx(); -} - static void Load_PLYP() { size_t size = SlGetFieldLength(); @@ -670,8 +823,8 @@ static void Save_PLYP() } static const ChunkHandler company_chunk_handlers[] = { - { 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY }, - { 'PLYX', Save_PLYX, Load_PLYX, nullptr, Check_PLYX, CH_RIFF }, + { 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_TABLE }, + { 'PLYX', nullptr, Load_PLYX, nullptr, Check_PLYX, CH_READONLY }, { 'PLYP', Save_PLYP, Load_PLYP, nullptr, nullptr, CH_RIFF }, }; diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 6e49bbc7ef..1f35c9fcbc 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -214,6 +214,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_VEHICLE_ECONOMY_AGE, XSCF_NULL, 1, 1, "slv_vehicle_economy_age", nullptr, nullptr, nullptr }, { XSLFI_TABLE_PATS, XSCF_NULL, 1, 1, "table_pats", nullptr, nullptr, nullptr }, + { XSLFI_TABLE_PLYR, XSCF_NULL, 1, 1, "table_plyr", nullptr, nullptr, nullptr }, { XSLFI_TABLE_MISC_SL, XSCF_NULL, 3, 3, "table_misc_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_SCRIPT_SL, XSCF_NULL, 1, 1, "table_script_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_NEWGRF_SL, XSCF_NULL, 2, 2, "table_newgrf_sl", nullptr, nullptr, nullptr }, diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index 2772dacb9a..909501481e 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -163,6 +163,7 @@ enum SlXvFeatureIndex { XSLFI_VEHICLE_ECONOMY_AGE, ///< See: SLV_VEHICLE_ECONOMY_AGE (PR #12141) XSLFI_TABLE_PATS, ///< Use upstream table format for PATS + XSLFI_TABLE_PLYR, ///< Use table format for PLYR XSLFI_TABLE_MISC_SL, ///< Use upstream table format for miscellaneous chunks: ///< v1: DATE, VIEW, MAPS ///< v2: SUBS, CMDL, CMPU, ERNW, DEPT, CAPY, ECMY, EIDS, ENGN, GOAL, GRPS, RAIL, OBJS, SIGN, PSAC, STPE, STPA From 3c53e9a9205b60041ffa98d3d196ca1ef2b43da9 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 21:28:46 +0100 Subject: [PATCH 098/107] Saveload: Add object ptr param to table object save/load helpers --- src/sl/cheat_sl.cpp | 6 +----- src/sl/saveload.cpp | 8 ++++---- src/sl/saveload.h | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/sl/cheat_sl.cpp b/src/sl/cheat_sl.cpp index 3b5df34315..52018ca58d 100644 --- a/src/sl/cheat_sl.cpp +++ b/src/sl/cheat_sl.cpp @@ -107,11 +107,7 @@ static void Load_CHTS() UnknownCheatHandler uch{}; SaveLoadTableData slt = SlTableHeader(GetCheatsDesc(false), &uch); - if (SlIterateArray() == -1) return; - SlObjectLoadFiltered(&_cheats, slt); - if (SlIterateArray() != -1) { - SlErrorCorruptFmt("Too many CHTS entries"); - } + SlLoadTableObjectChunk(slt, &_cheats); } else { size_t count = SlGetFieldLength(); SaveLoadTableData slt = SlTableHeaderOrRiff(GetCheatsDesc(false)); diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 44ce8427d0..15d3fecdd5 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2483,16 +2483,16 @@ SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTab return saveloads; } -void SlSaveTableObjectChunk(const SaveLoadTable &slt) +void SlSaveTableObjectChunk(const SaveLoadTable &slt, void *object) { SlSetArrayIndex(0); - SlObjectSaveFiltered(nullptr, slt); + SlObjectSaveFiltered(object, slt); } -void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt) +void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt, void *object) { if (SlIsTableChunk() && SlIterateArray() == -1) return; - SlObjectLoadFiltered(nullptr, slt); + SlObjectLoadFiltered(object, slt); if (SlIsTableChunk() && SlIterateArray() != -1) { uint32_t id = _sl.current_chunk_id; SlErrorCorruptFmt("Too many %s entries", ChunkIDDumper()(id)); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 4643d24390..2106aff551 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -1096,8 +1096,8 @@ void SlSkipTableHeader(); [[nodiscard]] SaveLoadTableData SlTableHeader(const NamedSaveLoadTable &slt, TableHeaderSpecialHandler *special_handler = nullptr); [[nodiscard]] SaveLoadTableData SlTableHeaderOrRiff(const NamedSaveLoadTable &slt); [[nodiscard]] SaveLoadTableData SlPrepareNamedSaveLoadTableForPtrOrNull(const NamedSaveLoadTable &slt); -void SlSaveTableObjectChunk(const SaveLoadTable &slt); -void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt); +void SlSaveTableObjectChunk(const SaveLoadTable &slt, void *object = nullptr); +void SlLoadTableOrRiffFiltered(const SaveLoadTable &slt, void *object = nullptr); void SlLoadTableWithArrayLengthPrefixesMissing(); void SlSetStructListLength(size_t length); @@ -1105,24 +1105,24 @@ size_t SlGetStructListLength(size_t limit); void SlSkipChunkContents(); -inline void SlSaveTableObjectChunk(const NamedSaveLoadTable &slt) +inline void SlSaveTableObjectChunk(const NamedSaveLoadTable &slt, void *object = nullptr) { - SlSaveTableObjectChunk(SlTableHeader(slt)); + SlSaveTableObjectChunk(SlTableHeader(slt), object); } -inline void SlLoadTableObjectChunk(const NamedSaveLoadTable &slt) +inline void SlLoadTableObjectChunk(const NamedSaveLoadTable &slt, void *object = nullptr) { - SlLoadTableOrRiffFiltered(SlTableHeader(slt)); + SlLoadTableOrRiffFiltered(SlTableHeader(slt), object); } -inline void SlLoadTableObjectChunk(const SaveLoadTable &slt) +inline void SlLoadTableObjectChunk(const SaveLoadTable &slt, void *object = nullptr) { - SlLoadTableOrRiffFiltered(slt); + SlLoadTableOrRiffFiltered(slt, object); } -inline void SlLoadTableOrRiffFiltered(const NamedSaveLoadTable &slt) +inline void SlLoadTableOrRiffFiltered(const NamedSaveLoadTable &slt, void *object = nullptr) { - SlLoadTableOrRiffFiltered(SlTableHeaderOrRiff(slt)); + SlLoadTableOrRiffFiltered(SlTableHeaderOrRiff(slt), object); } [[noreturn]] void CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3); From 5aa1c2ee04387701ecd11d7efe7e2efdde331aa6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 21:57:05 +0100 Subject: [PATCH 099/107] Saveload: Add gamma functions to header --- src/sl/saveload.cpp | 6 +++--- src/sl/saveload.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 15d3fecdd5..be2e445f94 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -685,7 +685,7 @@ size_t SlGetBytesWritten() * x = ((x & 0x7F) << 8) + SlReadByte(); * @return Return the value of the index */ -static uint SlReadSimpleGamma() +uint SlReadSimpleGamma() { uint i = SlReadByte(); if (HasBit(i, 7)) { @@ -727,7 +727,7 @@ static uint SlReadSimpleGamma() * @param i Index being written */ -static void SlWriteSimpleGamma(size_t i) +void SlWriteSimpleGamma(size_t i) { if (i >= (1 << 7)) { if (i >= (1 << 14)) { @@ -752,7 +752,7 @@ static void SlWriteSimpleGamma(size_t i) } /** Return how many bytes used to encode a gamma value */ -static inline uint SlGetGammaLength(size_t i) +uint SlGetGammaLength(size_t i) { return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28)); } diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 2106aff551..2e55cb1477 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -984,6 +984,10 @@ void SlSetLength(size_t length); size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld); size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt); +uint SlReadSimpleGamma(); +void SlWriteSimpleGamma(size_t i); +uint SlGetGammaLength(size_t i); + /** * Run proc, automatically prepending the written length * @param proc The callback procedure that is called From d67a2ea16771b424aa0c0eb591b4db57df5c7256 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jul 2024 22:00:12 +0100 Subject: [PATCH 100/107] Saveload: Use table format for bridge signal style map --- src/sl/bridge_signal_sl.cpp | 30 +++++++++++++++++++++++++----- src/sl/extended_ver_sl.cpp | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/sl/bridge_signal_sl.cpp b/src/sl/bridge_signal_sl.cpp index fab8e93da4..6da69d8154 100644 --- a/src/sl/bridge_signal_sl.cpp +++ b/src/sl/bridge_signal_sl.cpp @@ -16,6 +16,14 @@ static const NamedSaveLoad _long_bridge_signal_storage_desc[] = { NSL("signal_red_bits", SLE_VARVEC(LongBridgeSignalStorage, signal_red_bits, SLE_UINT64)), }; +struct BridgeSignalStyleMapStub { + std::vector signal_style_map; +}; + +static const NamedSaveLoad _bridge_signal_style_map_desc[] = { + NSL("signal_style_map", SLE_VARVEC(BridgeSignalStyleMapStub, signal_style_map, SLE_UINT32)), +}; + static void Load_XBSS() { SaveLoadTableData slt = SlTableHeaderOrRiff(_long_bridge_signal_storage_desc); @@ -40,15 +48,27 @@ static void Save_XBSS() static void Load_XBST() { - size_t count = SlGetFieldLength() / sizeof(uint32_t); - for (size_t i = 0; i < count; i++) { - _bridge_signal_style_map.insert(SlReadUint32()); + if (SlIsTableChunk()) { + SaveLoadTableData slt = SlTableHeader(_bridge_signal_style_map_desc); + BridgeSignalStyleMapStub stub{}; + SlLoadTableObjectChunk(slt, &stub); + _bridge_signal_style_map.insert(stub.signal_style_map.begin(), stub.signal_style_map.end()); + } else { + size_t count = SlGetFieldLength() / sizeof(uint32_t); + for (size_t i = 0; i < count; i++) { + _bridge_signal_style_map.insert(SlReadUint32()); + } } } static void Save_XBST() { - SlSetLength(_bridge_signal_style_map.size() * sizeof(uint32_t)); + SaveLoadTableData slt = SlTableHeader(_bridge_signal_style_map_desc); + + SlSetArrayIndex(0); + const size_t count = _bridge_signal_style_map.size(); + SlSetLength(SlGetGammaLength(count) + (count * 4)); + SlWriteSimpleGamma(count); for (uint32_t val : _bridge_signal_style_map) { SlWriteUint32(val); } @@ -56,7 +76,7 @@ static void Save_XBST() extern const ChunkHandler bridge_signal_chunk_handlers[] = { { 'XBSS', Save_XBSS, Load_XBSS, nullptr, nullptr, CH_SPARSE_TABLE }, - { 'XBST', Save_XBST, Load_XBST, nullptr, nullptr, CH_RIFF }, + { 'XBST', Save_XBST, Load_XBST, nullptr, nullptr, CH_TABLE }, }; extern const ChunkHandlerTable _bridge_signal_chunk_handlers(bridge_signal_chunk_handlers); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 1f35c9fcbc..d6c557ac57 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -180,7 +180,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_GRF_ROADSTOPS, XSCF_NULL, 3, 3, "grf_road_stops", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr }, - { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 3, 3, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, + { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 4, 4, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, { XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr }, { XSLFI_TOWN_SETTING_OVERRIDE, XSCF_NULL, 1, 1, "town_setting_override", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_SPARSE_EDGES, XSCF_NULL, 1, 1, "linkgraph_sparse_edges", nullptr, nullptr, nullptr }, From 422bcc3e26150ea44b3d7c366fd75ccb6a257412 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 00:16:33 +0100 Subject: [PATCH 101/107] TBTR: Fix minor formatting issues --- src/tbtr_template_vehicle_func.cpp | 72 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 2a7c95253a..ac192ae0ea 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -58,7 +58,7 @@ Money CalculateOverallTemplateCost(const TemplateVehicle *tv) { Money val = 0; - for (; tv; tv = tv->GetNextUnit()) { + for (; tv != nullptr; tv = tv->GetNextUnit()) { val += (Engine::Get(tv->engine_type))->GetCost(); } return val; @@ -68,7 +68,7 @@ Money CalculateOverallTemplateDisplayRunningCost(const TemplateVehicle *tv) { Money val = 0; - for (; tv; tv = tv->GetNextUnit()) { + for (; tv != nullptr; tv = tv->GetNextUnit()) { val += (Engine::Get(tv->engine_type))->GetDisplayRunningCost(); } return val; @@ -76,7 +76,7 @@ Money CalculateOverallTemplateDisplayRunningCost(const TemplateVehicle *tv) void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y, int height) { - if (!tv) return; + if (tv == nullptr) return; bool rtl = _current_text_dir == TD_RTL; @@ -91,7 +91,7 @@ void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y, int hei const TemplateVehicle *t = tv; int offset = rtl ? max_width : 0; - while (t) { + while (t != nullptr) { t->sprite_seq.Draw(offset + ((rtl ? -1 : 1) * t->image_dimensions.GetOffsetX()), t->image_dimensions.GetOffsetY() + ScaleSpriteTrad(10), t->colourmap, false); offset += (rtl ? -1 : 1) * t->image_dimensions.GetDisplayImageWidth(); @@ -99,10 +99,10 @@ void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y, int hei } } -// copy important stuff from the virtual vehicle to the template +/* Copy important stuff from the virtual vehicle to the template */ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev, Train *virt) { - if (prev) { + if (prev != nullptr) { prev->SetNext(tmp); tmp->SetPrev(prev); tmp->SetFirst(prev->First()); @@ -110,16 +110,16 @@ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev tmp->railtype = virt->railtype; tmp->owner = virt->owner; - // set the subtype but also clear the virtual flag while doing it + /* Set the subtype but also clear the virtual flag while doing it */ tmp->subtype = virt->subtype & ~(1 << GVSF_VIRTUAL); - // set the cargo type and capacity + /* Set the cargo type and capacity */ tmp->cargo_type = virt->cargo_type; tmp->cargo_subtype = virt->cargo_subtype; tmp->cargo_cap = virt->cargo_cap; SB(tmp->ctrl_flags, TVCF_REVERSED, 1, HasBit(virt->flags, VRF_REVERSE_DIRECTION) ? 1 : 0); - if (!virt->Previous()) { + if (virt->Previous() == nullptr) { uint cargo_weight = 0; uint full_cargo_weight = 0; for (const Train *u = virt; u != nullptr; u = u->Next()) { @@ -140,8 +140,8 @@ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev tmp->colourmap = GetUncachedTrainPaletteIgnoringGroup(virt); } -// create a full TemplateVehicle based train according to a virtual train -TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) +/* Create a full TemplateVehicle based train according to a virtual train */ +TemplateVehicle *TemplateVehicleFromVirtualTrain(Train *virt) { assert(virt != nullptr); @@ -149,7 +149,7 @@ TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) TemplateVehicle *tmp = nullptr; TemplateVehicle *prev = nullptr; - for (; virt; virt = virt->Next()) { + for (; virt != nullptr; virt = virt->Next()) { tmp = new TemplateVehicle(virt->engine_type); SetupTemplateVehicleFromVirtual(tmp, prev, virt); prev = tmp; @@ -159,7 +159,6 @@ TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) return tmp->First(); } -// forward declaration, defined in train_cmd.cpp CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16_t data, uint32_t user); Train *DeleteVirtualTrain(Train *chain, Train *to_del) @@ -174,7 +173,7 @@ Train *DeleteVirtualTrain(Train *chain, Train *to_del) } } -// retrieve template vehicle from template replacement that belongs to the given group +/* Retrieve template vehicle from template replacement that belongs to the given group */ TemplateVehicle *GetTemplateVehicleByGroupID(GroupID gid) { if (gid >= NEW_GROUP) return nullptr; @@ -198,7 +197,7 @@ bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType /* For standard rail engines, allow only those */ if (type == RAILTYPE_BEGIN || type == RAILTYPE_RAIL) { - while (tv) { + while (tv != nullptr) { if (tv->railtype != type) { return false; } @@ -207,7 +206,7 @@ bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType return true; } /* For electrified rail engines, standard wagons or engines are allowed to be included */ - while (tv) { + while (tv != nullptr) { if (tv->railtype == type) { return true; } @@ -257,11 +256,11 @@ Train *TemplateDepotVehicles::ContainsEngine(EngineID eid, Train *not_in) for (VehicleID id : this->vehicles) { Train *t = Train::GetIfValid(id); if (t == nullptr) continue; - // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' - // if 'not_in' is nullptr, no check is needed + /* Conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in'. + * If 'not_in' is nullptr, no check is needed. */ if (t->owner == _current_company - // If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will - // in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement + /* If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will. + * In case of t not a primary veh, we demand it to be a free wagon to consider it for replacement. */ && IsTrainUsableAsTemplateReplacementSource(t) && t->engine_type == eid && (not_in == nullptr || not_in->First() != t->First())) { @@ -278,7 +277,8 @@ void NeutralizeStatus(Train *t) DoCommand(0, t->index, 0, DC_EXEC, CMD_RENAME_VEHICLE, nullptr); } -TBTRDiffFlags TrainTemplateDifference(const Train *t, const TemplateVehicle *tv) { +TBTRDiffFlags TrainTemplateDifference(const Train *t, const TemplateVehicle *tv) +{ TBTRDiffFlags diff = TBTRDF_NONE; while (t != nullptr && tv != nullptr) { if (t->engine_type != tv->engine_type) { @@ -301,7 +301,7 @@ TBTRDiffFlags TrainTemplateDifference(const Train *t, const TemplateVehicle *tv) void BreakUpRemainders(Train *t) { - while (t) { + while (t != nullptr) { Train *move; if (HasBit(t->subtype, GVSF_ENGINE)) { move = t; @@ -314,7 +314,7 @@ void BreakUpRemainders(Train *t) } } -// make sure the real train wagon has the right cargo +/* Make sure the real train wagon has the right cargo */ void CopyWagonStatus(TemplateVehicle *from, Train *to) { to->cargo_type = from->cargo_type; @@ -324,7 +324,7 @@ void CopyWagonStatus(TemplateVehicle *from, Train *to) uint CountTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv) { uint count = 0; - if (!tv) return count; + if (tv == nullptr) return count; for (Train *t : Train::IterateFrontOnly()) { if (t->IsPrimaryVehicle() && t->group_id == g_id && TrainTemplateDifference(t, tv) != TBTRDF_NONE) { @@ -334,36 +334,34 @@ uint CountTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle * return count; } -// refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles +/* Refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles */ CommandCost CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags) { CommandCost cost(t->GetExpenseType(false)); - while (t && tv) { - // refit t as tv + while (t != nullptr && tv != nullptr) { + /* Refit t as tv */ uint32_t cb = GetCmdRefitVeh(t); cost.AddCost(DoCommand(t->tile, t->index, tv->cargo_type | tv->cargo_subtype << 8 | (1 << 16) | (1 << 31), flags, cb)); - // next t = t->GetNextUnit(); tv = tv->GetNextUnit(); } return cost; } -// set unit direction of each vehicle in t as is in tv, assume t and tv contain the same types of vehicles +/* Set unit direction of each vehicle in t as is in tv, assume t and tv contain the same types of vehicles */ CommandCost CmdSetTrainUnitDirectionFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags) { CommandCost cost(t->GetExpenseType(false)); - while (t && tv) { - // refit t as tv + while (t != nullptr && tv != nullptr) { + /* Refit t as tv */ if (HasBit(t->flags, VRF_REVERSE_DIRECTION) != HasBit(tv->ctrl_flags, TVCF_REVERSED)) { cost.AddCost(DoCommand(t->tile, t->index, true, flags, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE))); } - // next t = t->GetNextUnit(); tv = tv->GetNextUnit(); } @@ -378,7 +376,7 @@ CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex til { CommandCost cost(EXPENSES_NEW_VEHICLES); - for (; tv; tv = tv->GetNextUnit()) { + for (; tv != nullptr; tv = tv->GetNextUnit()) { cost.AddCost(DoCommand(tile, tv->engine_type, 0, DC_NONE, CMD_BUILD_VEHICLE)); } @@ -400,15 +398,15 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) const CargoID cargo_type = old_veh->cargo_type; const uint8_t cargo_subtype = old_veh->cargo_subtype; - // how much cargo has to be moved (if possible) + /* How much cargo has to be moved (if possible) */ uint remainingAmount = old_veh->cargo.TotalCount(); - // each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left + /* Each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left */ for (Train *tmp = new_head; tmp != nullptr && remainingAmount > 0; tmp = tmp->GetNextUnit()) { if (tmp->cargo_type == cargo_type && tmp->cargo_subtype == cargo_subtype) { - // calculate the free space for new cargo on the current vehicle + /* Calculate the free space for new cargo on the current vehicle */ uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount(); uint moveAmount = std::min(remainingAmount, curCap); - // move (parts of) the old vehicle's cargo onto the current vehicle of the new chain + /* Move (parts of) the old vehicle's cargo onto the current vehicle of the new chain */ if (moveAmount > 0) { old_veh->cargo.Shift(moveAmount, &tmp->cargo); remainingAmount -= moveAmount; From 78bf7c43e58fc8b75b5fb7fbfc3c3986106210b6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 00:19:49 +0100 Subject: [PATCH 102/107] TBTR: Fix wrong replacement count when train only differed by refit --- src/tbtr_template_vehicle_func.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index ac192ae0ea..48aea7835e 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -280,11 +280,12 @@ void NeutralizeStatus(Train *t) TBTRDiffFlags TrainTemplateDifference(const Train *t, const TemplateVehicle *tv) { TBTRDiffFlags diff = TBTRDF_NONE; + const bool check_refit_as_template = tv->refit_as_template; while (t != nullptr && tv != nullptr) { if (t->engine_type != tv->engine_type) { return TBTRDF_ALL; } - if (tv->refit_as_template && (t->cargo_type != tv->cargo_type || t->cargo_subtype != tv->cargo_subtype)) { + if (check_refit_as_template && (t->cargo_type != tv->cargo_type || t->cargo_subtype != tv->cargo_subtype)) { diff |= TBTRDF_REFIT; } if (HasBit(t->flags, VRF_REVERSE_DIRECTION) != HasBit(tv->ctrl_flags, TVCF_REVERSED)) { From e6bb811ca930fddc302c7c006e9dcd2f29830196 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 17:56:02 +0100 Subject: [PATCH 103/107] Saveload: Mark read-only chunks as CH_READONLY --- src/settings.cpp | 4 ++-- src/sl/engine_sl.cpp | 2 +- src/sl/station_sl.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index ab83152592..394530f758 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3897,9 +3897,9 @@ static void Check_PATX() } static const ChunkHandler setting_chunk_handlers[] = { - { 'OPTS', nullptr, Load_OPTS, nullptr, nullptr, CH_RIFF }, + { 'OPTS', nullptr, Load_OPTS, nullptr, nullptr, CH_READONLY }, MakeSaveUpstreamFeatureConditionalLoadUpstreamChunkHandler<'PATS', XSLFI_TABLE_PATS>(Load_PATS, nullptr, Check_PATS), - { 'PATX', nullptr, Load_PATX, nullptr, Check_PATX, CH_RIFF }, + { 'PATX', nullptr, Load_PATX, nullptr, Check_PATX, CH_READONLY }, }; extern const ChunkHandlerTable _setting_chunk_handlers(setting_chunk_handlers); diff --git a/src/sl/engine_sl.cpp b/src/sl/engine_sl.cpp index a86f6a9f6f..9787974274 100644 --- a/src/sl/engine_sl.cpp +++ b/src/sl/engine_sl.cpp @@ -117,7 +117,7 @@ void AfterLoadEngines() static const ChunkHandler engine_chunk_handlers[] = { MakeUpstreamChunkHandler<'EIDS', GeneralUpstreamChunkLoadInfo>(), MakeUpstreamChunkHandler<'ENGN', GeneralUpstreamChunkLoadInfo>(), - { 'ENGS', nullptr, Load_ENGS, nullptr, nullptr, CH_RIFF }, + { 'ENGS', nullptr, Load_ENGS, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _engine_chunk_handlers(engine_chunk_handlers); diff --git a/src/sl/station_sl.cpp b/src/sl/station_sl.cpp index 1555acdb6e..2177359f88 100644 --- a/src/sl/station_sl.cpp +++ b/src/sl/station_sl.cpp @@ -859,7 +859,7 @@ static void Load_DOCK() } static const ChunkHandler station_chunk_handlers[] = { - { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_ARRAY }, + { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_READONLY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY }, { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY }, { 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_READONLY }, From 29946e95b2bdb2cfd8499d139941dc9c40a79381 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 18:02:26 +0100 Subject: [PATCH 104/107] Fix refit in station when using articulated vehicles and simultaneous unload --- src/economy.cpp | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/economy.cpp b/src/economy.cpp index 3aff51a1e5..41e54be13d 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1658,6 +1658,22 @@ struct IsEmptyAction } }; +/** + * Action to check if a vehicle is unloading cargo. + */ +struct IsUnloadingAction +{ + /** + * Checks if the vehicle is unloading cargo. + * @param v Vehicle to be checked. + * @return true if v is unloading, false otherwise. + */ + bool operator()(const Vehicle *v) + { + return HasBit(v->vehicle_flags, VF_CARGO_UNLOADING); + } +}; + /** * Action to check whether a vehicle is wholly in the platform. */ @@ -1774,14 +1790,14 @@ struct FinalizeRefitAction /** * Refit a vehicle in a station. * @param v Vehicle to be refitted. + * @param v_start v->GetFirstEnginePart(). * @param consist_capleft Added cargo capacities in the consist. * @param st Station the vehicle is loading at. * @param next_station Possible next stations the vehicle can travel to. * @param new_cid Target cargo for refit. */ -static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, CargoStationIDStackSet next_station, CargoID new_cid) +static void HandleStationRefit(Vehicle *v, Vehicle *v_start, CargoArray &consist_capleft, Station *st, CargoStationIDStackSet next_station, CargoID new_cid) { - Vehicle *v_start = v->GetFirstEnginePart(); if (!IterateVehicleParts(v_start, IsEmptyAction())) return; if (v->type == VEH_TRAIN && !IterateVehicleParts(v_start, ThroughLoadTrainInPlatformAction())) return; @@ -2039,6 +2055,7 @@ static void LoadUnloadVehicle(Vehicle *front) CargoPayment *payment = front->cargo_payment; uint artic_part = 0; // Articulated part we are currently trying to load. (not counting parts without capacity) + bool suppress_artic_load = false; for (Vehicle *v = front; v != nullptr; v = v->Next()) { if (pull_through_mode && HasBit(Train::From(v)->flags, VRF_BEYOND_PLATFORM_END)) { if (v->cargo_cap != 0) { @@ -2076,7 +2093,10 @@ static void LoadUnloadVehicle(Vehicle *front) } platform_length_left -= length; } - if (v == front || !v->Previous()->HasArticulatedPart()) artic_part = 0; + if (v == front || !v->IsArticulatedPart()) { + artic_part = 0; + suppress_artic_load = false; + } if (v->cargo_cap == 0) continue; artic_part++; @@ -2151,7 +2171,9 @@ static void LoadUnloadVehicle(Vehicle *front) /* We have finished unloading (cargo count == 0) */ ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING); } - + if (front->current_order.IsRefit() && front->current_order.GetRefitCargo() != v->cargo_type) { + suppress_artic_load = true; + } continue; } @@ -2161,11 +2183,18 @@ static void LoadUnloadVehicle(Vehicle *front) /* This order has a refit, if this is the first vehicle part carrying cargo and the whole vehicle is empty, try refitting. */ if (front->current_order.IsRefit() && artic_part == 1) { - HandleStationRefit(v, consist_capleft, st, next_station, front->current_order.GetRefitCargo()); + Vehicle *v_start = v->GetFirstEnginePart(); + if (front->current_order.GetRefitCargo() != v->cargo_type && IterateVehicleParts(v_start, IsUnloadingAction())) { + suppress_artic_load = true; + continue; + } + HandleStationRefit(v, v_start, consist_capleft, st, next_station, front->current_order.GetRefitCargo()); ge = &st->goods[v->cargo_type]; ged = &ge->CreateData(); } + if (suppress_artic_load) continue; + /* Do not pick up goods when we have no-load set. */ if (GetLoadType(v) & OLFB_NO_LOAD) continue; From aba319e2a9b2915e5d4286a6025f9eb6df5a1555 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 18:26:26 +0100 Subject: [PATCH 105/107] Saveload: Use upstream chunk handler for ROAD road stops chunk --- src/sl/extended_ver_sl.h | 2 +- src/sl/station_sl.cpp | 54 +--------------------------------------- 2 files changed, 2 insertions(+), 54 deletions(-) diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index 909501481e..f9e530372c 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -167,7 +167,7 @@ enum SlXvFeatureIndex { XSLFI_TABLE_MISC_SL, ///< Use upstream table format for miscellaneous chunks: ///< v1: DATE, VIEW, MAPS ///< v2: SUBS, CMDL, CMPU, ERNW, DEPT, CAPY, ECMY, EIDS, ENGN, GOAL, GRPS, RAIL, OBJS, SIGN, PSAC, STPE, STPA - ///< v3: CAPA, CITY + ///< v3: CAPA, CITY, ROAD XSLFI_TABLE_SCRIPT_SL, ///< Use upstream table format for script chunks XSLFI_TABLE_NEWGRF_SL, ///< Use upstream table format for NewGRF/ID mapping chunks ///< In v1, NGRF chunks were saved incorrectly: see SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING diff --git a/src/sl/station_sl.cpp b/src/sl/station_sl.cpp index 2177359f88..3359e28c8a 100644 --- a/src/sl/station_sl.cpp +++ b/src/sl/station_sl.cpp @@ -156,22 +156,6 @@ void AfterLoadRoadStops() } } -static const SaveLoad _roadstop_desc[] = { - SLE_VAR(RoadStop, xy, SLE_UINT32), - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_45), - SLE_VAR(RoadStop, status, SLE_UINT8), - /* Index was saved in some versions, but this is not needed */ - SLE_CONDNULL(4, SL_MIN_VERSION, SLV_9), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_45), - SLE_CONDNULL(1, SL_MIN_VERSION, SLV_26), - - SLE_REF(RoadStop, next, REF_ROADSTOPS), - SLE_CONDNULL(2, SL_MIN_VERSION, SLV_45), - - SLE_CONDNULL(4, SL_MIN_VERSION, SLV_25), - SLE_CONDNULL(1, SLV_25, SLV_26), -}; - static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION), @@ -527,14 +511,6 @@ static void SetupDescs_STNN() _filtered_roadstop_speclist_desc = SlFilterObject(_roadstop_speclist_desc); } -std::vector _filtered_roadstop_desc; - -static void SetupDescs_ROADSTOP() -{ - _filtered_roadstop_desc = SlFilterObject(_roadstop_desc); -} - - static void RealSave_STNN(BaseStation *bst) { _num_specs = (uint8_t)bst->speclist.size(); @@ -824,34 +800,6 @@ static void Ptrs_STNN() } } -static void Save_ROADSTOP() -{ - SetupDescs_ROADSTOP(); - for (RoadStop *rs : RoadStop::Iterate()) { - SlSetArrayIndex(rs->index); - SlObjectSaveFiltered(rs, _filtered_roadstop_desc); - } -} - -static void Load_ROADSTOP() -{ - SetupDescs_ROADSTOP(); - int index; - while ((index = SlIterateArray()) != -1) { - RoadStop *rs = new (index) RoadStop(INVALID_TILE); - - SlObjectLoadFiltered(rs, _filtered_roadstop_desc); - } -} - -static void Ptrs_ROADSTOP() -{ - SetupDescs_ROADSTOP(); - for (RoadStop *rs : RoadStop::Iterate()) { - SlObjectPtrOrNullFiltered(rs, _filtered_roadstop_desc); - } -} - static void Load_DOCK() { extern void SlSkipArray(); @@ -861,7 +809,7 @@ static void Load_DOCK() static const ChunkHandler station_chunk_handlers[] = { { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_READONLY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY }, - { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY }, + MakeUpstreamChunkHandler<'ROAD', GeneralUpstreamChunkLoadInfo>(), { 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_READONLY }, }; From 0113bb1f64ba8099ad43bd9ab82eae32c2ce7f15 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 17 Jul 2024 18:59:12 +0100 Subject: [PATCH 106/107] Saveload: Use table format for INDY industry chunk --- src/sl/extended_ver_sl.cpp | 2 +- src/sl/extended_ver_sl.h | 4 +- src/sl/industry_sl.cpp | 127 +++++++++++++++++++------------------ 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index d6c557ac57..ff041720f8 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -218,7 +218,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TABLE_MISC_SL, XSCF_NULL, 3, 3, "table_misc_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_SCRIPT_SL, XSCF_NULL, 1, 1, "table_script_sl", nullptr, nullptr, nullptr }, { XSLFI_TABLE_NEWGRF_SL, XSCF_NULL, 2, 2, "table_newgrf_sl", nullptr, nullptr, nullptr }, - { XSLFI_TABLE_INDUSTRY_SL, XSCF_NULL, 1, 1, "table_industry_sl", nullptr, nullptr, nullptr }, + { XSLFI_TABLE_INDUSTRY_SL, XSCF_NULL, 2, 2, "table_industry_sl", nullptr, nullptr, nullptr }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr }, // This is the end marker }; diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index f9e530372c..1964c3b04a 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -171,7 +171,9 @@ enum SlXvFeatureIndex { XSLFI_TABLE_SCRIPT_SL, ///< Use upstream table format for script chunks XSLFI_TABLE_NEWGRF_SL, ///< Use upstream table format for NewGRF/ID mapping chunks ///< In v1, NGRF chunks were saved incorrectly: see SLBF_TABLE_ARRAY_LENGTH_PREFIX_MISSING - XSLFI_TABLE_INDUSTRY_SL, ///< Use upstream table format for industry chunks: IBLD, ITBL + XSLFI_TABLE_INDUSTRY_SL, ///< Use table format for industry chunks: + ///< v1: IBLD, ITBL + ///< v2: INDY XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/sl/industry_sl.cpp b/src/sl/industry_sl.cpp index a64e01a1ee..4956318607 100644 --- a/src/sl/industry_sl.cpp +++ b/src/sl/industry_sl.cpp @@ -17,76 +17,78 @@ static OldPersistentStorage _old_ind_persistent_storage; -static const SaveLoad _industry_desc[] = { - SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16), - SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16), - SLE_REF(Industry, town, REF_TOWN), - SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION), - SLE_CONDNULL( 2, SL_MIN_VERSION, SLV_61), ///< used to be industry's produced_cargo - SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDNULL( 3, SL_MIN_VERSION, SLV_61), ///< used to be industry's accepts_cargo - SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_VAR(Industry, prod_level, SLE_UINT8), - SLE_CONDARR(Industry, this_month_production, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR_X(Industry, this_month_production, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0)), - SLE_CONDARR_X(Industry, this_month_production, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1)), - SLE_CONDARR(Industry, this_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR_X(Industry, this_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0)), - SLE_CONDARR_X(Industry, this_month_transported, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1)), - SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDARR(Industry, last_month_production, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR_X(Industry, last_month_production, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0)), - SLE_CONDARR_X(Industry, last_month_production, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1)), - SLE_CONDARR(Industry, last_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR_X(Industry, last_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0)), - SLE_CONDARR_X(Industry, last_month_transported, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1)), +static const NamedSaveLoad _industry_desc[] = { + NSL("location.tile", SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6)), + NSL("location.tile", SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION)), + NSL("location.w", SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16)), + NSL("location.h", SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16)), + NSL("town", SLE_REF(Industry, town, REF_TOWN)), + NSL("neutral_station", SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_61)), // used to be industry's produced_cargo + NSL("produced_cargo", SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("produced_cargo", SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("incoming_cargo_waiting", SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("incoming_cargo_waiting", SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("produced_cargo_waiting", SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("produced_cargo_waiting", SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("production_rate", SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("production_rate", SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("", SLE_CONDNULL(3, SL_MIN_VERSION, SLV_61)), // used to be industry's accepts_cargo + NSL("accepts_cargo", SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("accepts_cargo", SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("prod_level", SLE_VAR(Industry, prod_level, SLE_UINT8)), + NSL("this_month_production", SLE_CONDARR(Industry, this_month_production, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("this_month_production", SLE_CONDARR_X(Industry, this_month_production, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0))), + NSL("this_month_production", SLE_CONDARR_X(Industry, this_month_production, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1))), + NSL("this_month_transported", SLE_CONDARR(Industry, this_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("this_month_transported", SLE_CONDARR_X(Industry, this_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0))), + NSL("this_month_transported", SLE_CONDARR_X(Industry, this_month_transported, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1))), + NSL("last_month_pct_transported", SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("last_month_pct_transported", SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("last_month_production", SLE_CONDARR(Industry, last_month_production, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("last_month_production", SLE_CONDARR_X(Industry, last_month_production, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0))), + NSL("last_month_production", SLE_CONDARR_X(Industry, last_month_production, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1))), + NSL("last_month_transported", SLE_CONDARR(Industry, last_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("last_month_transported", SLE_CONDARR_X(Industry, last_month_transported, SLE_FILE_U16 | SLE_VAR_U32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 0, 0))), + NSL("last_month_transported", SLE_CONDARR_X(Industry, last_month_transported, SLE_UINT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_INDUSTRY_CARGO_TOTALS, 1))), - SLE_VAR(Industry, counter, SLE_UINT16), + NSL("counter", SLE_VAR(Industry, counter, SLE_UINT16)), - SLE_VAR(Industry, type, SLE_UINT8), - SLE_VAR(Industry, owner, SLE_UINT8), - SLE_VAR(Industry, random_colour, SLE_UINT8), - SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), - SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION), - SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), - SLE_CONDVAR(Industry, ctlflags, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), + NSL("type", SLE_VAR(Industry, type, SLE_UINT8)), + NSL("owner", SLE_VAR(Industry, owner, SLE_UINT8)), + NSL("random_colour", SLE_VAR(Industry, random_colour, SLE_UINT8)), + NSL("last_prod_year", SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31)), + NSL("last_prod_year", SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION)), + NSL("was_cargo_delivered", SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8)), + NSL("ctlflags", SLE_CONDVAR(Industry, ctlflags, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION)), - SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION), - SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), - SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), - SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION), - SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), - SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION), + NSL("founder", SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION)), + NSL("construction_date", SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION)), + NSL("construction_type", SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION)), + NSL("", SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS)), + NSL("last_cargo_accepted_at", SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION)), + NSL("selected_layout", SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION)), + NSL("exclusive_supplier", SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION)), + NSL("exclusive_consumer", SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION)), - SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161), - SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION), + NSL("", SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161)), + NSL("psa", SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION)), - SLE_CONDNULL(1, SLV_82, SLV_197), // random_triggers - SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION), - SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION), + NSL("", SLE_CONDNULL(1, SLV_82, SLV_197)), // random_triggers + NSL("random", SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION)), + NSL("text", SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION)), - SLE_CONDNULL(32, SLV_2, SLV_144), // old reserved space + NSL("", SLE_CONDNULL(32, SLV_2, SLV_144)), // old reserved space }; static void Save_INDY() { + SaveLoadTableData slt = SlTableHeader(_industry_desc); + /* Write the industries */ for (Industry *ind : Industry::Iterate()) { SlSetArrayIndex(ind->index); - SlObject(ind, _industry_desc); + SlObjectSaveFiltered(ind, slt); } } @@ -102,13 +104,14 @@ static void Save_TIDS() static void Load_INDY() { - int index; + SaveLoadTableData slt = SlTableHeaderOrRiff(_industry_desc); Industry::ResetIndustryCounts(); + int index; while ((index = SlIterateArray()) != -1) { Industry *i = new (index) Industry(); - SlObject(i, _industry_desc); + SlObjectLoadFiltered(i, slt); /* Before savegame version 161, persistent storages were not stored in a pool. */ if (IsSavegameVersionBefore(SLV_161) && !IsSavegameVersionBefore(SLV_76)) { @@ -133,8 +136,10 @@ static void Load_TIDS() static void Ptrs_INDY() { + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(_industry_desc); + for (Industry *i : Industry::Iterate()) { - SlObject(i, _industry_desc); + SlObjectPtrOrNullFiltered(i, slt); } } @@ -191,7 +196,7 @@ static void Load_ITBL() } static const ChunkHandler industry_chunk_handlers[] = { - { 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, nullptr, CH_ARRAY }, + { 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, nullptr, CH_TABLE }, { 'IIDS', Save_IIDS, Load_IIDS, nullptr, nullptr, CH_TABLE }, { 'TIDS', Save_TIDS, Load_TIDS, nullptr, nullptr, CH_TABLE }, { 'IBLD', Save_IBLD, Load_IBLD, nullptr, nullptr, CH_TABLE }, From 0d1e24b8fd0b3a5602ebd75b9541ff3f37bdc734 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 18 Jul 2024 17:02:47 +0100 Subject: [PATCH 107/107] Fix 32b8ec34f: Incorrect perm storage dump in debug window Due to merge conflict resolution error --- src/newgrf_debug_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index f3a6497fbc..f286ca024c 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -779,7 +779,7 @@ struct NewGRFInspectWindow : Window { if (psa[j] != 0) last_non_blank = j + 1; } const uint psa_limit = (last_non_blank + 3) & ~3; - for (uint j = 0; j < psa_limit; j += 44) { + for (uint j = 0; j < psa_limit; j += 4) { this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]); } if (last_non_blank != (uint)psa.size()) {