From 34758d0921655643878791ab61f6f248d8280958 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 9 Apr 2024 17:54:42 +0100 Subject: [PATCH 01/10] Change: Allow string mapping by function instead of pointer. This allows mapping of strings to objects that may be moved between loading stages. --- src/newgrf.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 0446fbd736..e5794882f7 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -452,12 +452,24 @@ static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = nul * Information for mapping static StringIDs. */ struct StringIDMapping { - uint32_t grfid; ///< Source NewGRF. - StringID source; ///< Source StringID (GRF local). - StringID *target; ///< Destination for mapping result. + uint32_t grfid; ///< Source NewGRF. + StringID source; ///< Source StringID (GRF local). + std::function func; ///< Function for mapping result. + + StringIDMapping(uint32_t grfid, StringID source, std::function &&func) : grfid(grfid), source(source), func(std::move(func)) { } }; -typedef std::vector StringIDMappingVector; -static StringIDMappingVector _string_to_grf_mapping; +static std::vector _string_to_grf_mapping; + +/** + * Record a static StringID for getting translated later. + * @param source Source StringID (GRF local). + * @param func Function to call to set the mapping result. + */ +static void AddStringForMapping(StringID source, std::function &&func) +{ + func(STR_UNDEFINED); + _string_to_grf_mapping.emplace_back(_cur.grffile->grfid, source, std::move(func)); +} /** * Record a static StringID for getting translated later. @@ -466,8 +478,7 @@ static StringIDMappingVector _string_to_grf_mapping; */ static void AddStringForMapping(StringID source, StringID *target) { - *target = STR_UNDEFINED; - _string_to_grf_mapping.push_back({_cur.grffile->grfid, source, target}); + AddStringForMapping(source, [target](StringID str) { *target = str; }); } /** @@ -2128,7 +2139,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte break; case 0x1D: // Station Class name - AddStringForMapping(buf->ReadWord(), &StationClass::Get(statspec->cls_id)->name); + AddStringForMapping(buf->ReadWord(), [statspec](StringID str) { StationClass::Get(statspec->cls_id)->name = str; }); break; default: @@ -4148,8 +4159,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea } case 0x09: { // Class name - ObjectClass *objclass = ObjectClass::Get(spec->cls_id); - AddStringForMapping(buf->ReadWord(), &objclass->name); + AddStringForMapping(buf->ReadWord(), [spec](StringID str) { ObjectClass::Get(spec->cls_id)->name = str; }); break; } @@ -4845,7 +4855,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR break; case 0x0B: // Road Stop Class name - AddStringForMapping(buf->ReadWord(), &RoadStopClass::Get(rs->cls_id)->name); + AddStringForMapping(buf->ReadWord(), [rs](StringID str) { RoadStopClass::Get(rs->cls_id)->name = str; }); break; case 0x0C: // The draw mode @@ -9918,7 +9928,7 @@ extern void InitGRFTownGeneratorNames(); static void AfterLoadGRFs() { for (StringIDMapping &it : _string_to_grf_mapping) { - *it.target = MapGRFStringID(it.grfid, it.source); + it.func(MapGRFStringID(it.grfid, it.source)); } _string_to_grf_mapping.clear(); From 052f42132750db6c1a5bbe6308090d48908418fc Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 9 Apr 2024 17:54:42 +0100 Subject: [PATCH 02/10] Change: Use vector/iterators/algorithms instead of C-array/loops for NewGRF classes. --- src/airport_gui.cpp | 2 +- src/newgrf.cpp | 2 ++ src/newgrf_class.h | 13 +++---- src/newgrf_class_func.h | 76 ++++++++++++++--------------------------- 4 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 3b346d2629..a52b876d7c 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -546,7 +546,7 @@ public: if (change_class) { /* If that fails, select the first available airport * from the first class where airports are available. */ - for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { + for (AirportClassID j = APC_BEGIN; j < AirportClass::GetClassCount(); j++) { AirportClass *apclass = AirportClass::Get(j); for (uint i = 0; i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index e5794882f7..662fc3e38b 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -458,6 +458,8 @@ struct StringIDMapping { StringIDMapping(uint32_t grfid, StringID source, std::function &&func) : grfid(grfid), source(source), func(std::move(func)) { } }; + +/** Strings to be mapped during load. */ static std::vector _string_to_grf_mapping; /** diff --git a/src/newgrf_class.h b/src/newgrf_class.h index 38e068a881..cd80d65410 100644 --- a/src/newgrf_class.h +++ b/src/newgrf_class.h @@ -19,17 +19,14 @@ template class NewGRFClass { private: - uint ui_count; ///< Number of specs in this class potentially available to the user. + uint ui_count = 0; ///< Number of specs in this class potentially available to the user. std::vector spec; ///< List of specifications. /** * The actual classes. - * @note We store pointers to members of this array in various places outside this class (e.g. to 'name' for GRF string resolving). - * Thus this must be a static array, and cannot be a self-resizing vector or similar. + * @note This may be reallocated during initialization so pointers may be invalidated. */ - static NewGRFClass classes[Tmax]; - - void ResetClass(); + static inline std::vector> classes; /** Initialise the defaults. */ static void InsertDefaults(); @@ -38,8 +35,12 @@ public: uint32_t global_id; ///< Global ID for class, e.g. 'DFLT', 'WAYP', etc. StringID name; ///< Name of this class. + /* Public constructor as emplace_back needs access. */ + NewGRFClass(uint32_t global_id, StringID name) : global_id(global_id), name(name) { } + void Insert(Tspec *spec); + Tid Index() const { return static_cast(std::distance(&*std::cbegin(NewGRFClass::classes), this)); } /** Get the number of allocated specs within the class. */ uint GetSpecCount() const { return static_cast(this->spec.size()); } /** Get the number of potentially user-available specs within the class. */ diff --git a/src/newgrf_class_func.h b/src/newgrf_class_func.h index b3de6ba9c1..ef9490a0c1 100644 --- a/src/newgrf_class_func.h +++ b/src/newgrf_class_func.h @@ -11,35 +11,19 @@ #include "table/strings.h" -/** Instantiate the array. */ -template -NewGRFClass NewGRFClass::classes[Tmax]; - -/** Reset the class, i.e. clear everything. */ -template -void NewGRFClass::ResetClass() -{ - this->global_id = 0; - this->name = STR_EMPTY; - this->ui_count = 0; - - this->spec.clear(); -} - /** Reset the classes, i.e. clear everything. */ template void NewGRFClass::Reset() { - for (Tid i = (Tid)0; i < Tmax; i++) { - classes[i].ResetClass(); - } + NewGRFClass::classes.clear(); + NewGRFClass::classes.shrink_to_fit(); - InsertDefaults(); + NewGRFClass::InsertDefaults(); } /** * Allocate a class with a given global class ID. - * @param cls_id The global class id, such as 'DFLT'. + * @param global_id The global class id, such as 'DFLT'. * @return The (non global!) class ID for the class. * @note Upon allocating the same global class ID for a * second time, this first allocation will be given. @@ -47,19 +31,19 @@ void NewGRFClass::Reset() template Tid NewGRFClass::Allocate(uint32_t global_id) { - for (Tid i = (Tid)0; i < Tmax; i++) { - if (classes[i].global_id == global_id) { - /* ClassID is already allocated, so reuse it. */ - return i; - } else if (classes[i].global_id == 0) { - /* This class is empty, so allocate it to the global id. */ - classes[i].global_id = global_id; - return i; - } + auto found = std::find_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [global_id](const auto &cls) { return cls.global_id == global_id; }); + + /* Id is already allocated, so reuse it. */ + if (found != std::end(NewGRFClass::classes)) return found->Index(); + + /* More slots available, allocate a slot to the global id. */ + if (NewGRFClass::classes.size() < Tmax) { + auto &cls = NewGRFClass::classes.emplace_back(global_id, STR_EMPTY); + return cls.Index(); } GrfMsg(2, "ClassAllocate: already allocated {} classes, using default", Tmax); - return (Tid)0; + return static_cast(0); } /** @@ -82,7 +66,7 @@ void NewGRFClass::Insert(Tspec *spec) template void NewGRFClass::Assign(Tspec *spec) { - assert(spec->cls_id < Tmax); + assert(static_cast(spec->cls_id) < NewGRFClass::classes.size()); Get(spec->cls_id)->Insert(spec); } @@ -94,8 +78,8 @@ void NewGRFClass::Assign(Tspec *spec) template NewGRFClass *NewGRFClass::Get(Tid cls_id) { - assert(cls_id < Tmax); - return classes + cls_id; + assert(static_cast(cls_id) < NewGRFClass::classes.size()); + return &NewGRFClass::classes[cls_id]; } /** @@ -105,9 +89,7 @@ NewGRFClass *NewGRFClass::Get(Tid cls_id) template uint NewGRFClass::GetClassCount() { - uint i; - for (i = 0; i < Tmax && classes[i].global_id != 0; i++) {} - return i; + return static_cast(NewGRFClass::classes.size()); } /** @@ -117,11 +99,7 @@ uint NewGRFClass::GetClassCount() template uint NewGRFClass::GetUIClassCount() { - uint cnt = 0; - for (uint i = 0; i < Tmax && classes[i].global_id != 0; i++) { - if (classes[i].GetUISpecCount() > 0) cnt++; - } - return cnt; + return std::count_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [](const auto &cls) { return cls.GetUISpecCount() > 0; }); } /** @@ -132,9 +110,9 @@ uint NewGRFClass::GetUIClassCount() template Tid NewGRFClass::GetUIClass(uint index) { - for (uint i = 0; i < Tmax && classes[i].global_id != 0; i++) { - if (classes[i].GetUISpecCount() == 0) continue; - if (index-- == 0) return (Tid)i; + for (const auto &cls : NewGRFClass::classes) { + if (cls.GetUISpecCount() == 0) continue; + if (index-- == 0) return cls.Index(); } NOT_REACHED(); } @@ -193,15 +171,11 @@ int NewGRFClass::GetUIFromIndex(int index) const template const Tspec *NewGRFClass::GetByGrf(uint32_t grfid, uint16_t local_id, int *index) { - uint j; - - for (Tid i = (Tid)0; i < Tmax; i++) { - uint count = static_cast(classes[i].spec.size()); - for (j = 0; j < count; j++) { - const Tspec *spec = classes[i].spec[j]; + for (const auto &cls : NewGRFClass::classes) { + for (const auto &spec : cls.spec) { if (spec == nullptr) continue; if (spec->grf_prop.grffile->grfid == grfid && spec->grf_prop.local_id == local_id) { - if (index != nullptr) *index = j; + if (index != nullptr) *index = static_cast(std::distance(cls.spec.data(), &spec)); return spec; } } From 77f27e08049c4428e2ef0d2a5feff5c26bfc4b32 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 9 Apr 2024 17:54:43 +0100 Subject: [PATCH 03/10] Change: Expose NewGRF classes and specs as spans and simplify iteration. This replaces some index-based loops with range loops. --- src/airport_gui.cpp | 20 +++++++++----------- src/newgrf_class.h | 12 ++++++++++++ src/newgrf_roadstop.cpp | 13 ++++++------- src/object_gui.cpp | 7 +++---- src/rail_gui.cpp | 14 +++++--------- src/road_gui.cpp | 14 +++++--------- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index a52b876d7c..2d5378e72f 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -241,8 +241,8 @@ class BuildAirportWindow : public PickerWindowBase { { DropDownList list; - for (uint i = 0; i < AirportClass::GetClassCount(); i++) { - list.push_back(MakeDropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i)); + for (const auto &cls : AirportClass::Classes()) { + list.push_back(MakeDropDownListStringItem(cls.name, cls.Index())); } return list; @@ -322,8 +322,8 @@ public: switch (widget) { case WID_AP_CLASS_DROPDOWN: { Dimension d = {0, 0}; - for (uint i = 0; i < AirportClass::GetClassCount(); i++) { - d = maxdim(d, GetStringBoundingBox(AirportClass::Get((AirportClassID)i)->name)); + for (const auto &cls : AirportClass::Classes()) { + d = maxdim(d, GetStringBoundingBox(cls.name)); } d.width += padding.width; d.height += padding.height; @@ -546,14 +546,12 @@ public: if (change_class) { /* If that fails, select the first available airport * from the first class where airports are available. */ - for (AirportClassID j = APC_BEGIN; j < AirportClass::GetClassCount(); j++) { - AirportClass *apclass = AirportClass::Get(j); - for (uint i = 0; i < apclass->GetSpecCount(); i++) { - const AirportSpec *as = apclass->GetSpec(i); + for (const auto &cls : AirportClass::Classes()) { + for (const auto &as : cls.Specs()) { if (as->IsAvailable()) { - _selected_airport_class = j; - this->vscroll->SetCount(apclass->GetSpecCount()); - this->SelectOtherAirport(i); + _selected_airport_class = cls.Index(); + this->vscroll->SetCount(cls.GetSpecCount()); + this->SelectOtherAirport(as->GetIndex()); return; } } diff --git a/src/newgrf_class.h b/src/newgrf_class.h index cd80d65410..2097a9eaca 100644 --- a/src/newgrf_class.h +++ b/src/newgrf_class.h @@ -38,6 +38,18 @@ public: /* Public constructor as emplace_back needs access. */ NewGRFClass(uint32_t global_id, StringID name) : global_id(global_id), name(name) { } + /** + * Get read-only span of specs of this class. + * @return Read-only span of specs. + */ + std::span Specs() const { return this->spec; } + + /** + * Get read-only span of all classes of this type. + * @return Read-only span of classes. + */ + static std::span const> Classes() { return NewGRFClass::classes; } + void Insert(Tspec *spec); Tid Index() const { return static_cast(std::distance(&*std::cbegin(NewGRFClass::classes), this)); } diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp index 482bce1e6a..f45f051dee 100644 --- a/src/newgrf_roadstop.cpp +++ b/src/newgrf_roadstop.cpp @@ -465,13 +465,12 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri */ bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype) { - for (uint i = 0; i < RoadStopClass::GetClassCount(); i++) { + for (const auto &cls : RoadStopClass::Classes()) { /* Ignore the waypoint class. */ - if (i == ROADSTOP_CLASS_WAYP) continue; - const RoadStopClass *roadstopclass = RoadStopClass::Get((RoadStopClassID)i); + if (cls.Index() == ROADSTOP_CLASS_WAYP) continue; /* Ignore the default class with only the default station. */ - if (i == ROADSTOP_CLASS_DFLT && roadstopclass->GetSpecCount() == 1) continue; - if (GetIfClassHasNewStopsByType(roadstopclass, rs, roadtype)) return true; + if (cls.Index() == ROADSTOP_CLASS_DFLT && cls.GetSpecCount() == 1) continue; + if (GetIfClassHasNewStopsByType(&cls, rs, roadtype)) return true; } return false; } @@ -485,8 +484,8 @@ bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype) */ bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype) { - for (uint j = 0; j < roadstopclass->GetSpecCount(); j++) { - if (GetIfStopIsForType(roadstopclass->GetSpec(j), rs, roadtype)) return true; + for (const auto spec : roadstopclass->Specs()) { + if (GetIfStopIsForType(spec, rs, roadtype)) return true; } return false; } diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 7ea9fd37df..9199c55538 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -145,10 +145,9 @@ public: this->object_classes.clear(); - for (uint i = 0; i < ObjectClass::GetClassCount(); i++) { - ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i); - if (objclass->GetUISpecCount() == 0) continue; // Is this needed here? - object_classes.push_back((ObjectClassID)i); + for (const auto &cls : ObjectClass::Classes()) { + if (cls.GetUISpecCount() == 0) continue; // Is this needed here? + object_classes.push_back(cls.Index()); } this->object_classes.Filter(this->string_filter); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index a3ebd0843d..d3dfd94db6 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1109,15 +1109,11 @@ public: this->station_classes.clear(); - for (uint i = 0; i < StationClass::GetClassCount(); i++) { - StationClassID station_class_id = (StationClassID)i; - if (station_class_id == StationClassID::STAT_CLASS_WAYP) { - // Skip waypoints. - continue; - } - StationClass *station_class = StationClass::Get(station_class_id); - if (station_class->GetUISpecCount() == 0) continue; - station_classes.push_back(station_class_id); + for (const auto &cls : StationClass::Classes()) { + /* Skip waypoints. */ + if (cls.Index() == STAT_CLASS_WAYP) continue; + if (cls.GetUISpecCount() == 0) continue; + station_classes.push_back(cls.Index()); } if (_railstation.newstations) { diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 6bc38298ce..8637c910f1 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1201,7 +1201,7 @@ public: this->FinishInitNested(TRANSPORT_ROAD); this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION; - if (!newstops || _roadstop_gui_settings.roadstop_class >= (int)RoadStopClass::GetClassCount()) { + if (!newstops || _roadstop_gui_settings.roadstop_class >= RoadStopClass::GetClassCount()) { /* There's no new stops available or the list has reduced in size. * Now, set the default road stops as selected. */ _roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT; @@ -1264,14 +1264,10 @@ public: this->roadstop_classes.clear(); - for (uint i = 0; i < RoadStopClass::GetClassCount(); i++) { - RoadStopClassID rs_id = (RoadStopClassID)i; - if (rs_id == ROADSTOP_CLASS_WAYP) { - // Skip waypoints. - continue; - } - RoadStopClass *rs_class = RoadStopClass::Get(rs_id); - if (GetIfClassHasNewStopsByType(rs_class, this->roadStopType, _cur_roadtype)) this->roadstop_classes.push_back(rs_id); + for (const auto &cls : RoadStopClass::Classes()) { + /* Skip waypoints. */ + if (cls.Index() == ROADSTOP_CLASS_WAYP) continue; + if (GetIfClassHasNewStopsByType(&cls, this->roadStopType, _cur_roadtype)) this->roadstop_classes.push_back(cls.Index()); } if (this->ShowNewStops()) { From df8eeb1b10965a78d9ded5fdf77d799549a72608 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Tue, 9 Apr 2024 22:57:39 +0200 Subject: [PATCH 04/10] Codechange: use C++ algorithms to determine the SaveLoadFormat --- src/saveload/saveload.cpp | 103 +++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2f57886118..28b65ba920 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -2628,23 +2628,28 @@ struct SaveLoadFormat { uint8_t max_compression; ///< the maximum compression level of this format }; +static const uint32_t SAVEGAME_TAG_LZO = TO_BE32X('OTTD'); +static const uint32_t SAVEGAME_TAG_NONE = TO_BE32X('OTTN'); +static const uint32_t SAVEGAME_TAG_ZLIB = TO_BE32X('OTTZ'); +static const uint32_t SAVEGAME_TAG_LZMA = TO_BE32X('OTTX'); + /** The different saveload formats known/understood by OpenTTD. */ static const SaveLoadFormat _saveload_formats[] = { #if defined(WITH_LZO) /* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */ - {"lzo", TO_BE32X('OTTD'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, + {"lzo", SAVEGAME_TAG_LZO, CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, #else - {"lzo", TO_BE32X('OTTD'), nullptr, nullptr, 0, 0, 0}, + {"lzo", SAVEGAME_TAG_LZO, nullptr, nullptr, 0, 0, 0}, #endif /* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */ - {"none", TO_BE32X('OTTN'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, + {"none", SAVEGAME_TAG_NONE, CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, #if defined(WITH_ZLIB) /* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */ - {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter, CreateSaveFilter, 0, 6, 9}, + {"zlib", SAVEGAME_TAG_ZLIB, CreateLoadFilter, CreateSaveFilter, 0, 6, 9}, #else - {"zlib", TO_BE32X('OTTZ'), nullptr, nullptr, 0, 0, 0}, + {"zlib", SAVEGAME_TAG_ZLIB, nullptr, nullptr, 0, 0, 0}, #endif #if defined(WITH_LIBLZMA) /* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves. @@ -2652,9 +2657,9 @@ static const SaveLoadFormat _saveload_formats[] = { * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50% * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much. * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */ - {"lzma", TO_BE32X('OTTX'), CreateLoadFilter, CreateSaveFilter, 0, 2, 9}, + {"lzma", SAVEGAME_TAG_LZMA, CreateLoadFilter, CreateSaveFilter, 0, 2, 9}, #else - {"lzma", TO_BE32X('OTTX'), nullptr, nullptr, 0, 0, 0}, + {"lzma", SAVEGAME_TAG_LZMA, nullptr, nullptr, 0, 0, 0}, #endif }; @@ -2885,6 +2890,49 @@ SaveOrLoadResult SaveWithFilter(std::shared_ptr writer, bool threade } } +/** + * Determines the SaveLoadFormat that is connected to the given tag. + * When the given tag is known, that format is chosen and a check on the validity of the version is performed. + * Otherwise a fallback to an ancient buggy format using LZO is chosen. + * @param tag The tag from the header describing the savegame compression/format. + * @param raw_version The raw version from the savegame header. + * @return The SaveLoadFormat to use for attempting to open the savegame. + */ +static const SaveLoadFormat *DetermineSaveLoadFormat(uint32_t tag, uint32_t raw_version) +{ + auto fmt = std::find_if(std::begin(_saveload_formats), std::end(_saveload_formats), [tag](const auto &fmt) { return fmt.tag == tag; }); + if (fmt != std::end(_saveload_formats)) { + /* Check version number */ + _sl_version = (SaveLoadVersion)(TO_BE32(raw_version) >> 16); + /* Minor is not used anymore from version 18.0, but it is still needed + * in versions before that (4 cases) which can't be removed easy. + * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */ + _sl_minor_version = (TO_BE32(raw_version) >> 8) & 0xFF; + + Debug(sl, 1, "Loading savegame version {}", _sl_version); + + /* Is the version higher than the current? */ + if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME); + if (_sl_version >= SLV_START_PATCHPACKS && _sl_version <= SLV_END_PATCHPACKS) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK); + return fmt; + } + + Debug(sl, 0, "Unknown savegame type, trying to load it as the buggy format"); + _sl.lf->Reset(); + _sl_version = SL_MIN_VERSION; + _sl_minor_version = 0; + + /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */ + fmt = std::find_if(std::begin(_saveload_formats), std::end(_saveload_formats), [](const auto &fmt) { return fmt.tag == SAVEGAME_TAG_LZO; }); + if (fmt == std::end(_saveload_formats)) { + /* Who removed the LZO savegame format definition? When built without LZO support, + * the formats must still list it just without a method to read the file. + * The caller of this function has to check for the existence of load function. */ + NOT_REACHED(); + } + return fmt; +} + /** * Actually perform the loading of a "non-old" savegame. * @param reader The filter to read the savegame from. @@ -2906,46 +2954,7 @@ static SaveOrLoadResult DoLoad(std::shared_ptr reader, bool load_che if (_sl.lf->Read((uint8_t*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); /* see if we have any loader for this type. */ - const SaveLoadFormat *fmt = _saveload_formats; - for (;;) { - /* No loader found, treat as version 0 and use LZO format */ - if (fmt == endof(_saveload_formats)) { - Debug(sl, 0, "Unknown savegame type, trying to load it as the buggy format"); - _sl.lf->Reset(); - _sl_version = SL_MIN_VERSION; - _sl_minor_version = 0; - - /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */ - fmt = _saveload_formats; - for (;;) { - if (fmt == endof(_saveload_formats)) { - /* Who removed LZO support? */ - NOT_REACHED(); - } - if (fmt->tag == TO_BE32X('OTTD')) break; - fmt++; - } - break; - } - - if (fmt->tag == hdr[0]) { - /* check version number */ - _sl_version = (SaveLoadVersion)(TO_BE32(hdr[1]) >> 16); - /* Minor is not used anymore from version 18.0, but it is still needed - * in versions before that (4 cases) which can't be removed easy. - * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */ - _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF; - - Debug(sl, 1, "Loading savegame version {}", _sl_version); - - /* Is the version higher than the current? */ - if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME); - if (_sl_version >= SLV_START_PATCHPACKS && _sl_version <= SLV_END_PATCHPACKS) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK); - break; - } - - fmt++; - } + const SaveLoadFormat *fmt = DetermineSaveLoadFormat(hdr[0], hdr[1]); /* loader for this savegame type is not implemented? */ if (fmt->init_load == nullptr) { From 1773c5b810dd5138a0879b02e3bd5e56e7e7ddda Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 9 Apr 2024 23:16:20 +0100 Subject: [PATCH 05/10] Change: Increase object/station/roadstop class limit. (#12094) The class limit is arbitrary and not stored in game state. This change prevents all entities in classes after the 255th class from being dumped into the first class. --- src/newgrf_object.h | 8 ++++---- src/newgrf_roadstop.h | 10 +++++----- src/newgrf_station.h | 10 +++++----- src/road_cmd.h | 2 +- src/station_cmd.h | 4 ++-- src/waypoint_cmd.h | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 0d224410ab..8b17a7c7a6 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -45,10 +45,10 @@ static const uint8_t OBJECT_SIZE_1X1 = 0x11; ///< The value of a NewGRF's size p void ResetObjects(); /** Class IDs for objects. */ -enum ObjectClassID : uint8_t { - OBJECT_CLASS_BEGIN = 0, ///< The lowest valid value - OBJECT_CLASS_MAX = 0xFF, ///< Maximum number of classes. - INVALID_OBJECT_CLASS = 0xFF, ///< Class for the less fortunate. +enum ObjectClassID : uint16_t { + OBJECT_CLASS_BEGIN = 0, ///< The lowest valid value + OBJECT_CLASS_MAX = UINT16_MAX, ///< Maximum number of classes. + INVALID_OBJECT_CLASS = UINT16_MAX, ///< Class for the less fortunate. }; /** Allow incrementing of ObjectClassID variables */ DECLARE_POSTFIX_INCREMENT(ObjectClassID) diff --git a/src/newgrf_roadstop.h b/src/newgrf_roadstop.h index 8c231dc4ca..03df70e9fa 100644 --- a/src/newgrf_roadstop.h +++ b/src/newgrf_roadstop.h @@ -22,11 +22,11 @@ /** The maximum amount of roadstops a single GRF is allowed to add */ static const int NUM_ROADSTOPS_PER_GRF = UINT16_MAX - 1; -enum RoadStopClassID : uint8_t { - ROADSTOP_CLASS_BEGIN = 0, ///< The lowest valid value - ROADSTOP_CLASS_DFLT = 0, ///< Default road stop class. - ROADSTOP_CLASS_WAYP, ///< Waypoint class (unimplemented: this is reserved for future use with road waypoints). - ROADSTOP_CLASS_MAX = 255, ///< Maximum number of classes. +enum RoadStopClassID : uint16_t { + ROADSTOP_CLASS_BEGIN = 0, ///< The lowest valid value + ROADSTOP_CLASS_DFLT = 0, ///< Default road stop class. + ROADSTOP_CLASS_WAYP, ///< Waypoint class (unimplemented: this is reserved for future use with road waypoints). + ROADSTOP_CLASS_MAX = UINT16_MAX, ///< Maximum number of classes. }; DECLARE_POSTFIX_INCREMENT(RoadStopClassID) diff --git a/src/newgrf_station.h b/src/newgrf_station.h index be9fa03dfe..2924ff4288 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -80,11 +80,11 @@ struct StationResolverObject : public ResolverObject { uint32_t GetDebugID() const override; }; -enum StationClassID : uint8_t { - STAT_CLASS_BEGIN = 0, ///< the lowest valid value - STAT_CLASS_DFLT = 0, ///< Default station class. - STAT_CLASS_WAYP, ///< Waypoint class. - STAT_CLASS_MAX = 255, ///< Maximum number of classes. +enum StationClassID : uint16_t { + STAT_CLASS_BEGIN = 0, ///< the lowest valid value + STAT_CLASS_DFLT = 0, ///< Default station class. + STAT_CLASS_WAYP, ///< Waypoint class. + STAT_CLASS_MAX = UINT16_MAX, ///< Maximum number of classes. }; /** Allow incrementing of StationClassID variables */ diff --git a/src/road_cmd.h b/src/road_cmd.h index 3a957f2a15..71883ddada 100644 --- a/src/road_cmd.h +++ b/src/road_cmd.h @@ -14,7 +14,7 @@ #include "road_type.h" #include "command_type.h" -enum RoadStopClassID : uint8_t; +enum RoadStopClassID : uint16_t; void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt); void UpdateNearestTownForRoadTiles(bool invalidate); diff --git a/src/station_cmd.h b/src/station_cmd.h index ef566af5fd..00f98a0d35 100644 --- a/src/station_cmd.h +++ b/src/station_cmd.h @@ -13,8 +13,8 @@ #include "command_type.h" #include "station_type.h" -enum StationClassID : uint8_t; -enum RoadStopClassID : uint8_t; +enum StationClassID : uint16_t; +enum RoadStopClassID : uint16_t; extern Town *AirportGetNearestTown(const struct AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist); extern uint8_t GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint distance); diff --git a/src/waypoint_cmd.h b/src/waypoint_cmd.h index b64ef0496c..02914124c6 100644 --- a/src/waypoint_cmd.h +++ b/src/waypoint_cmd.h @@ -13,7 +13,7 @@ #include "command_type.h" #include "station_type.h" -enum StationClassID : uint8_t; +enum StationClassID : uint16_t; CommandCost CmdBuildRailWaypoint(DoCommandFlag flags, TileIndex start_tile, Axis axis, uint8_t width, uint8_t height, StationClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent); CommandCost CmdRemoveFromRailWaypoint(DoCommandFlag flags, TileIndex start, TileIndex end, bool keep_rail); From f0f97c698ba609d555f4363019f4d0e20066d9d0 Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 10 Apr 2024 04:40:30 +0000 Subject: [PATCH 06/10] Update: Translations from eints norwegian (bokmal): 11 changes by eriksorngard russian: 5 changes by Ln-Wolf spanish: 5 changes by MontyMontana portuguese (brazilian): 7 changes by pasantoro --- src/lang/brazilian_portuguese.txt | 14 +++++++------- src/lang/norwegian_bokmal.txt | 17 +++++++++++------ src/lang/russian.txt | 5 +++++ src/lang/spanish.txt | 5 +++++ 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 0c5f79b7fa..548f4c9894 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1620,7 +1620,7 @@ STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Área máxima q STR_CONFIG_SETTING_SERVICEATHELIPAD :Manutenção automática de helicópteros em heliportos: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Efetuar manutenção de helicópteros após cada pouso, mesmo se não existir um depósito no aeroporto -STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Ligar ferramentas de paisagismo com construção de trilhos/estradas/água/aeroportos: {STRING} +STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Ligar ferramentas de paisagismo com construção de trilhos/estrada/aeroporto: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Ao abrir a barra de ferramentas de construção para um tipo de transporte, abrir também a barra de ferramentas de paisagismo STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Cor do solo usada no minimapa: {STRING} @@ -1642,9 +1642,9 @@ STR_CONFIG_SETTING_SCROLLMODE :Comportamento d STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :Comportamento de movimentação do mapa. A opção "posição do mouse travada" não funciona em todos os sistemas, tais como versões baseadas na web, telas sensíveis ao toque, Linux com Wayland e outros ###length 4 STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :Mover visualização com o Botão Direito, posição do mouse travada -STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Mover mapa com o Botão Direito, posição do mouse travada -STR_CONFIG_SETTING_SCROLLMODE_RMB :Mover mapa com o Botão Direito do Mouse -STR_CONFIG_SETTING_SCROLLMODE_LMB :Mover mapa com o Botão Esquerdo do Mouse +STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Mover mapa com Botão Direito, posição do mouse travada +STR_CONFIG_SETTING_SCROLLMODE_RMB :Mover mapa com Botão Direito do Mouse +STR_CONFIG_SETTING_SCROLLMODE_LMB :Mover mapa com Botão Esquerdo do Mouse STR_CONFIG_SETTING_SMOOTH_SCROLLING :Suavizar deslocamento da visualização: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Controlar como a visualização principal se move para uma localização específica ao clicar no minimapa ou quando é dado um comando para ir até um objeto específico no mapa. Se ativado, a visualização se move suavemente. Se desativado, a visualização salta diretamente para o destino escolhido @@ -1840,7 +1840,7 @@ STR_CONFIG_SETTING_SERVINT_DISABLED :Desativado STR_CONFIG_SETTING_NOSERVICE :Desativar manutenção quando as quebras estão desativadas: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Quando ativado, veículos não recebem manutenção se não podem quebrar -STR_CONFIG_SETTING_STATION_LENGTH_LOADING_PENALTY :Penalizar a velocidade de carregamento para trens que são mais longos que a estação: {STRING} +STR_CONFIG_SETTING_STATION_LENGTH_LOADING_PENALTY :Penalizar velocidade de carregamento para trens mais longos que a estação: {STRING} STR_CONFIG_SETTING_STATION_LENGTH_LOADING_PENALTY_HELPTEXT :Quando ativado, os trens que são muito compridos para a estação são carregados mais lentamente do que um trem que cabe na estação. Esta configuração não afeta a geração de rotas STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Ativar limite de velocidade para vagões: {STRING} @@ -4781,7 +4781,7 @@ STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Interrom STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Ativar/Desativar interrupção quando uma mensagem de registro da IA for igual a esta sequência de caracteres STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Parar em: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Parar em -STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Quando uma mensagem de registro da IA for igual a esta sequência de caracteres, o jogo é pausado +STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}O jogo é pausado quando uma mensagem de registro da IA for igual a esta sequência de caracteres STR_AI_DEBUG_MATCH_CASE :{BLACK}Diferenciar maiúsculas/minúsculas STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Ativar/Desativar correspondência de maiúsculas/minúsculas quando comparar as mensagens de registro da IA com a sequência de caracteres de parada STR_AI_DEBUG_CONTINUE :{BLACK}Continuar @@ -5125,7 +5125,7 @@ STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL :{WHITE}... não # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} fica muito longo depois da substituição -STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Nenhuma regra de substituição automática/renovação aplicada +STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Nenhuma regra de substituição/renovação automática aplicada STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(limite de dinheiro) STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO :{WHITE}O novo veículo não pode transportar {STRING} STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT :{WHITE}O novo veículo não pode ser adaptado na ordem {NUM} diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 189de7b286..3953b8868c 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -3490,6 +3490,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Veitype STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF-variabel 60+x parameter (heksadesimal) # Sprite aligner window +STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Forskyver sprite: ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Forskyver sprite: Handling 0xA, {COMMA} ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Forskyver sprite: Handling 0x5, type {HEX}, {COMMA} ({STRING}:{NUM}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Neste sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Fortsett til neste normale sprite og hopp over enhver pseudo-/omfargings-/skrifttype- sprite, samt start om ved begynnelsen STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Gå til sprite @@ -3498,6 +3501,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Forrige STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Fortsett til forrige normale sprite og hopp over enhver pseudo-/omfargings-/skrifttype- sprite, samt start om ved begynnelsen STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Forhåndsvisning av valgt sprite. Innrettingen ignoreres når spriten tegnes STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Flytt på ikonet for å endre X- og Y-forskyvningene. Ctrl+klikk for å flytte ikonet åtte enheter om gangen +STR_SPRITE_ALIGNER_SPRITE :{STRING}:{NUM} ###length 2 STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Offset sentrert @@ -3531,15 +3535,15 @@ STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} krev STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF-filen den var laget for å oversette STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :For mange NewGRF-er er innlastet STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Å laste inn {1:STRING} som statisk NewGRF med {2:STRING} kan forårsake synkroniseringsfeil -STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Uventet sprite (figur {3:NUM}) -STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Ukjent Handling 0 egenskap {4:HEX} (figur {3:NUM}) +STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Uventet sprite (sprite {3:NUM}) +STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Ukjent Handling 0 egenskap {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Forsøk på å bruke ugyldig ID (sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} inneholder en ødelagt sprite. Alle ødelagte spriter blir vist som røde spørsmålstegn (?). -STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Inneholder flere Handling 8-oppføringer (figur {3:NUM}) -STR_NEWGRF_ERROR_READ_BOUNDS :Leste forbi slutten av pseudo-sprite (figur {3:NUM}) -STR_NEWGRF_ERROR_GRM_FAILED :Etterspurte GRF-ressurser ikke tilgjengelig (figur {3:NUM}) +STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Inneholder flere Handling 8-oppføringer (sprite {3:NUM}) +STR_NEWGRF_ERROR_READ_BOUNDS :Leste forbi slutten av pseudo-sprite (sprite {3:NUM}) +STR_NEWGRF_ERROR_GRM_FAILED :Etterspurte GRF-ressurser ikke tilgjengelig (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} ble deaktivert av {STRING} -STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Ugyldig/ukjent sprite layoutformat (figur {3:NUM}) +STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Ugyldig/ukjent sprite layoutformat (sprite {3:NUM}) STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG :For mange elementer i fortegnelse over eiendomsverdier (sprite {3:NUM}, property {4:HEX}) STR_NEWGRF_ERROR_INDPROD_CALLBACK :Ugyldig industriprodukjson callback (sprite {3:NUM}, "{2:STRING}") @@ -5834,6 +5838,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/russian.txt b/src/lang/russian.txt index 1bd5fab913..56dcbbf559 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -3663,6 +3663,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Тип доро STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}Параметр переменной NewGRF 60+x (шестнадцатеричный) # Sprite aligner window +STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Выравнивающий спрайт: ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Выравнивающий спрайт: Действие 0xA, {COMMA} ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Выравнивающий спрайт: Действие 0x5, type {HEX}, {COMMA} ({STRING}:{NUM}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Следующий спрайт STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Перейти к следующему нормальному спрайту, пропуская изменяющие цвет, шрифтовые, псевдоспрайты. Переход из конца списка к первому спрайту. STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Перейти к спрайту @@ -3671,6 +3674,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Пред STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Перейти к предыдущему нормальному спрайту, пропуская изменяющие цвет, шрифтовые, псевдоспрайты. Переход из начала списка к последнему спрайту. STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Представление выбранного спрайта. Выравнивание не учитывается при прорисовке этого спрайта. STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Двигайте спрайт, изменяя смещение по осям X и Y. С помощью Ctrl+щелчка можно сдвигать спрайты на 8 единиц. +STR_SPRITE_ALIGNER_SPRITE :{STRING}:{NUM} ###length 2 STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Смещение в центре @@ -6056,6 +6060,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/spanish.txt b/src/lang/spanish.txt index 9f7dcd3a99..e4921fda2c 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -3489,6 +3489,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Tipo de carrete STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}Parámetro de variable NewGRF 60+x (hexadecimal) # Sprite aligner window +STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Alineando sprite: ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Alineando sprite: Acción 0xA, {COMMA} ({STRING}:{NUM}) +STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Alineando sprite: Acción 0x5, tipo {HEX}, {COMMA} ({STRING}:{NUM}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Siguiente sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Va al siguiente sprite (ignorando pseudosprites, sprites recoloreados y sprites de fuente) y pasa del último al primer sprite STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Ir a sprite @@ -3497,6 +3500,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Sprite a STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Salta al sprite anterior (ignorando pseudosprites, sprites recoloreados y sprites de fuente) y pasa del primer al último sprite STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representa el sprite seleccionado. Su alineamiento es ignorado al dibujarlo STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Mover el sprite, cambiando los ajustes X e Y. Ctrl+clic mueve el sprite ocho unidades de una sola vez +STR_SPRITE_ALIGNER_SPRITE :{STRING}:{NUM} ###length 2 STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Desviación (offset) centrada @@ -5833,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} From 1b4bb1d38a03753ebaa0e9513b0a9f32c9c07803 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 10 Apr 2024 10:50:44 +0200 Subject: [PATCH 07/10] Codefix: [CMake] use the UTC0 date for our ISODATE (#12470) --- cmake/scripts/FindVersion.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/scripts/FindVersion.cmake b/cmake/scripts/FindVersion.cmake index c4ff99a7fd..5fd4be4949 100644 --- a/cmake/scripts/FindVersion.cmake +++ b/cmake/scripts/FindVersion.cmake @@ -49,7 +49,8 @@ if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") string(SUBSTRING "${FULLHASH}" 0 10 SHORTHASH) # Get the last commit date - execute_process(COMMAND ${GIT_EXECUTABLE} show -s --pretty=format:%ci HEAD + set(ENV{TZ} "UTC0") + execute_process(COMMAND ${GIT_EXECUTABLE} show -s --date=iso-local --pretty=format:%cd HEAD OUTPUT_VARIABLE COMMITDATE OUTPUT_STRIP_TRAILING_WHITESPACE WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} From 21b640b5ffb8e331dfd68e8508647267caa2feb4 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 10 Apr 2024 06:51:11 +0200 Subject: [PATCH 08/10] Codechange: simplify president name generation --- src/strings.cpp | 60 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/strings.cpp b/src/strings.cpp index e02ae292a4..7ee8497cd5 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1802,55 +1802,49 @@ static const char _initial_name_letters[] = { 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', }; -static void GenAndCoName(StringBuilder &builder, uint32_t arg) +static std::span GetSurnameOptions() { - const char * const *base; - uint num; + if (_settings_game.game_creation.landscape == LT_TOYLAND) return _silly_surname_list; + return _surname_list; +} - if (_settings_game.game_creation.landscape == LT_TOYLAND) { - base = _silly_surname_list; - num = lengthof(_silly_surname_list); - } else { - base = _surname_list; - num = lengthof(_surname_list); - } +/** + * Get the surname of the president with the given seed. + * @param seed The seed the surname was generated from. + * @return The surname. + */ +static const char *GetSurname(uint32_t seed) +{ + auto surname_options = GetSurnameOptions(); + return surname_options[surname_options.size() * GB(seed, 16, 8) >> 8]; +} - builder += base[num * GB(arg, 16, 8) >> 8]; +static void GenAndCoName(StringBuilder &builder, uint32_t seed) +{ + builder += GetSurname(seed); builder += " & Co."; } -static void GenPresidentName(StringBuilder &builder, uint32_t x) +static void GenPresidentName(StringBuilder &builder, uint32_t seed) { - char initial[] = "?. "; - const char * const *base; - uint num; - uint i; + builder += _initial_name_letters[std::size(_initial_name_letters) * GB(seed, 0, 8) >> 8]; + builder += ". "; - initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; - builder += initial; - - i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8; - if (i < sizeof(_initial_name_letters)) { - initial[0] = _initial_name_letters[i]; - builder += initial; + /* The second initial is optional. */ + size_t index = (std::size(_initial_name_letters) + 35) * GB(seed, 8, 8) >> 8; + if (index < std::size(_initial_name_letters)) { + builder += _initial_name_letters[index]; + builder += ". "; } - if (_settings_game.game_creation.landscape == LT_TOYLAND) { - base = _silly_surname_list; - num = lengthof(_silly_surname_list); - } else { - base = _surname_list; - num = lengthof(_surname_list); - } - - builder += base[num * GB(x, 16, 8) >> 8]; + builder += GetSurname(seed); } static void GetSpecialNameString(StringBuilder &builder, int ind, StringParameters &args) { switch (ind) { case 1: // not used - builder += _silly_company_names[std::min(args.GetNextParameter(), lengthof(_silly_company_names) - 1)]; + builder += _silly_company_names[std::min(args.GetNextParameter(), std::size(_silly_company_names) - 1)]; return; case 2: // used for Foobar & Co company names From 144bcbbaf18154f048663d66b35a1f1d9c76579b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 10 Apr 2024 18:27:30 +0100 Subject: [PATCH 09/10] Fix: Use clear() to clear std::string. (#12471) --- src/industry_gui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index f682f0cc13..78d7ae0f27 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -165,14 +165,14 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy uint cargotype = local_id << 16 | use_input; GetCargoSuffix(cargotype, cst, ind, ind_type, indspec, suffixes[j]); } else { - suffixes[j].text[0] = '\0'; + suffixes[j].text.clear(); suffixes[j].display = CSD_CARGO; } } } else { /* Compatible behaviour with old 3-in-2-out scheme */ for (uint j = 0; j < lengthof(suffixes); j++) { - suffixes[j].text[0] = '\0'; + suffixes[j].text.clear(); suffixes[j].display = CSD_CARGO; } switch (use_input) { @@ -204,7 +204,7 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy */ void GetCargoSuffix(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, CargoID cargo, uint8_t slot, CargoSuffix &suffix) { - suffix.text[0] = '\0'; + suffix.text.clear(); suffix.display = CSD_CARGO; if (!IsValidCargoID(cargo)) return; if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) { From a42aa1a0861807e85c65387e5871658070f7a9ec Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 10 Apr 2024 21:32:21 +0100 Subject: [PATCH 10/10] Codechange: Remove cargo_suffix C-array from GetIndustryString. (#12472) The information is pushed onto a vector, so string ownership can be moved there instead of using a pointer into to the CargoSuffix array. --- src/industry_gui.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 78d7ae0f27..e981f61daf 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1559,21 +1559,22 @@ protected: /* Industry name */ SetDParam(p++, i->index); - static CargoSuffix cargo_suffix[INDUSTRY_NUM_OUTPUTS]; - /* Get industry productions (CargoID, production, suffix, transported) */ struct CargoInfo { - CargoID cargo_id; - uint16_t production; - const char *suffix; - uint transported; + CargoID cargo_id; ///< Cargo ID. + uint16_t production; ///< Production last month. + uint transported; ///< Percent transported last month. + std::string suffix; ///< Cargo suffix. + + CargoInfo(CargoID cargo_id, uint16_t production, uint transported, std::string &&suffix) : cargo_id(cargo_id), production(production), transported(transported), suffix(std::move(suffix)) {} }; std::vector cargos; for (auto itp = std::begin(i->produced); itp != std::end(i->produced); ++itp) { if (!IsValidCargoID(itp->cargo)) continue; - GetCargoSuffix(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, itp->cargo, itp - std::begin(i->produced), cargo_suffix[itp - std::begin(i->produced)]); - cargos.push_back({ itp->cargo, itp->history[LAST_MONTH].production, cargo_suffix[itp - std::begin(i->produced)].text.c_str(), ToPercent8(itp->history[LAST_MONTH].PctTransported()) }); + CargoSuffix cargo_suffix; + GetCargoSuffix(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, itp->cargo, itp - std::begin(i->produced), cargo_suffix); + cargos.emplace_back(itp->cargo, itp->history[LAST_MONTH].production, ToPercent8(itp->history[LAST_MONTH].PctTransported()), std::move(cargo_suffix.text)); } switch (static_cast(this->industries.SortType())) { @@ -1610,11 +1611,11 @@ protected: /* Display first 3 cargos */ for (size_t j = 0; j < std::min(3, cargos.size()); j++) { - CargoInfo ci = cargos[j]; + CargoInfo &ci = cargos[j]; SetDParam(p++, STR_INDUSTRY_DIRECTORY_ITEM_INFO); SetDParam(p++, ci.cargo_id); SetDParam(p++, ci.production); - SetDParamStr(p++, ci.suffix); + SetDParamStr(p++, std::move(ci.suffix)); SetDParam(p++, ci.transported); }