From 2e626d70e8a80f5db9cca48efd3daec3f9d28e1a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 18 Sep 2021 12:43:22 +0100 Subject: [PATCH 01/43] Debug: Add minimum_life to house debug window --- src/table/newgrf_debug_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 3fbe5407e3..7d7156d9b9 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -502,7 +502,7 @@ class NIHHouse : public NIHelper { print(buffer); seprintf(buffer, lastof(buffer), " extra_flags: 0x%X", hs->extra_flags); print(buffer); - seprintf(buffer, lastof(buffer), " remove_rating_decrease: %u", hs->remove_rating_decrease); + seprintf(buffer, lastof(buffer), " remove_rating_decrease: %u, minimum_life: %u", hs->remove_rating_decrease, hs->minimum_life); print(buffer); seprintf(buffer, lastof(buffer), " population: %u, mail_generation: %u", hs->population, hs->mail_generation); print(buffer); From 9ad5e4baf0e198e32dfeb6295c07ccab62ae5e7d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 18 Sep 2021 23:51:08 +0100 Subject: [PATCH 02/43] Add maximum speed (fully loaded) to train window sort list --- src/group_gui.cpp | 3 +-- src/lang/english.txt | 1 + src/vehicle_gui.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- src/vehicle_gui_base.h | 4 ++-- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 3201f4e9ef..6de975130c 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -731,8 +731,7 @@ public: return; case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu - ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, - (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : this->vehicle_sorter_non_ground_veh_disable_mask); + ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, this->GetSorterDisableMask(this->vli.vtype)); return; case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu diff --git a/src/lang/english.txt b/src/lang/english.txt index 820866a6e5..797fd7db60 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -306,6 +306,7 @@ STR_SORT_BY_LENGTH :Length STR_SORT_BY_LIFE_TIME :Remaining lifetime STR_SORT_BY_TIMETABLE_DELAY :Timetable delay STR_SORT_BY_AVG_ORDER_OCCUPANCY :Average order occupancy +STR_SORT_BY_MAX_SPEED_LOADED :Maximum speed (fully loaded) STR_SORT_BY_FACILITY :Station type STR_SORT_BY_WAITING_TOTAL :Total waiting cargo STR_SORT_BY_WAITING_AVAILABLE :Available waiting cargo diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index bd3337acdf..e83dfc7a2f 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -66,6 +66,7 @@ static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleLengthSorter; static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleTimeToLiveSorter; static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleTimetableDelaySorter; static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleAverageOrderOccupancySorter; +static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleMaxSpeedLoadedSorter; static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupLengthSorter; static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupTotalProfitThisYearSorter; static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupTotalProfitLastYearSorter; @@ -96,6 +97,7 @@ enum VehicleSortType VST_TIME_TO_LIVE, VST_TIMETABLE_DELAY, VST_AVERAGE_ORDER_OCCUPANCY, + VST_MAX_SPEED_LOADED, }; BaseVehicleListWindow::VehicleGroupSortFunction * const BaseVehicleListWindow::vehicle_group_none_sorter_funcs[] = { @@ -114,6 +116,7 @@ BaseVehicleListWindow::VehicleGroupSortFunction * const BaseVehicleListWindow::v &VehicleIndividualToGroupSorterWrapper, &VehicleIndividualToGroupSorterWrapper, &VehicleIndividualToGroupSorterWrapper, + &VehicleIndividualToGroupSorterWrapper, }; const StringID BaseVehicleListWindow::vehicle_group_none_sorter_names[] = { @@ -132,6 +135,7 @@ const StringID BaseVehicleListWindow::vehicle_group_none_sorter_names[] = { STR_SORT_BY_LIFE_TIME, STR_SORT_BY_TIMETABLE_DELAY, STR_SORT_BY_AVG_ORDER_OCCUPANCY, + STR_SORT_BY_MAX_SPEED_LOADED, INVALID_STRING_ID }; @@ -477,12 +481,15 @@ DropDownList BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplac /* cached values for VehicleNameSorter to spare many GetString() calls */ static const Vehicle *_last_vehicle[2] = { nullptr, nullptr }; +static btree::btree_map _vehicle_max_speed_loaded; + void BaseVehicleListWindow::SortVehicleList() { if (this->vehgroups.Sort()) return; /* invalidate cached values for name sorter - vehicle names could change */ _last_vehicle[0] = _last_vehicle[1] = nullptr; + _vehicle_max_speed_loaded.clear(); } void DepotSortList(VehicleList *list) @@ -1606,6 +1613,29 @@ static bool VehicleAverageOrderOccupancySorter(const Vehicle * const &a, const V return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } +/** Sort vehicles by the max speed (fully loaded) */ +static bool VehicleMaxSpeedLoadedSorter(const Vehicle * const &a, const Vehicle * const &b) +{ + auto get_max_speed_loaded = [](const Train * const v) -> int { + auto res = _vehicle_max_speed_loaded.insert({ v->index, 0 }); + if (!res.second) { + /* This vehicle's speed was already in _vehicle_max_speed_loaded */ + return res.first->second; + } + int loaded_weight = 0; + for (const Train *u = v; u != nullptr; u = u->Next()) { + loaded_weight += u->GetWeightWithoutCargo() + u->GetCargoWeight(u->cargo_cap); + } + + int loaded_max_speed = GetTrainEstimatedMaxAchievableSpeed(v, loaded_weight, v->GetDisplayMaxSpeed()); + res.first->second = loaded_max_speed; + return loaded_max_speed; + }; + + int r = get_max_speed_loaded(Train::From(a)) - get_max_speed_loaded(Train::From(b)); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); +} + void InitializeGUI() { MemSetT(&_grouping, 0); @@ -2034,6 +2064,16 @@ void BaseVehicleListWindow::UpdateVehicleGroupBy(GroupBy group_by) } } +uint BaseVehicleListWindow::GetSorterDisableMask(VehicleType type) const +{ + uint mask = 0; + if (this->grouping == GB_NONE) { + if (type != VEH_TRAIN && type != VEH_ROAD) mask |= (1 << VST_LENGTH); + if (type != VEH_TRAIN || _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) mask |= (1 << VST_MAX_SPEED_LOADED); + } + return mask; +} + /** * Window for the (old) vehicle listing. * @@ -2250,7 +2290,7 @@ public: case WID_VL_SORT_BY_PULLDOWN: // Select sorting criteria dropdown menu ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_VL_SORT_BY_PULLDOWN, 0, - (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : this->vehicle_sorter_non_ground_veh_disable_mask, 0, DDSF_LOST_FOCUS); + this->GetSorterDisableMask(this->vli.vtype), 0, DDSF_LOST_FOCUS); return; case WID_VL_FILTER_BY_CARGO: // Cargo filter dropdown diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index c72d165657..f9e5d58996 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -127,8 +127,6 @@ public: static VehicleGroupSortFunction * const vehicle_group_none_sorter_funcs[]; static VehicleGroupSortFunction * const vehicle_group_shared_orders_sorter_funcs[]; - const uint vehicle_sorter_non_ground_veh_disable_mask = (1 << 11); // STR_SORT_BY_LENGTH - BaseVehicleListWindow(WindowDesc *desc, WindowNumber wno); void OnInit() override; @@ -173,6 +171,8 @@ public: NOT_REACHED(); } } + + uint GetSorterDisableMask(VehicleType type) const; }; uint GetVehicleListHeight(VehicleType type, uint divisor = 1); From 06b9881a051e61c8cd8bee046457d2ae06695f37 Mon Sep 17 00:00:00 2001 From: Woelfi Von Wolfhausen <65563631+WoelfiVW@users.noreply.github.com> Date: Sun, 26 Sep 2021 17:57:37 +0200 Subject: [PATCH 03/43] Fix typos Fix some typos regarding formality and noun-is-written-big-rules --- src/lang/german.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lang/german.txt b/src/lang/german.txt index 458300e6c6..b4946432bd 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1651,14 +1651,14 @@ STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Lege das Layout STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS :Automatische Entfernung von Signalen während der Errichtung von Bahntrassen: {STRING} STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS_HELPTEXT :Automatische Entfernung von Signalen während der Errichtung der Bahntrasse, wenn diese sich im Weg befinden. Hinweis: Dies kann zu Unfällen führen! STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT :Zeitraffer Geschwindigkeitslimit: {STRING} -STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_HELPTEXT :Limit wie schnell das Spiel läuft, wenn Zeitraffer aktiviert ist. 0= unlimitiert (so schnell, wie ihr Computer es erlaubt). Eingaben unter 100% können das Spiel verlangsamen. Das obere Limit hängt von den technischen Spezifikationen ihres Computer ab und kann großen Einfluss auf das Spiel haben +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_HELPTEXT :Limit wie schnell das Spiel läuft, wenn Zeitraffer aktiviert ist. 0= unlimitiert (so schnell, wie Ihr Computer es erlaubt). Eingaben unter 100% können das Spiel verlangsamen. Das obere Limit hängt von den technischen Spezifikationen Ihres Computers ab und kann großen Einfluss auf das Spiel haben STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_VAL :{NUM}% normale Spielgeschwindigkeit -STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :Keine Beschränkung (so schnell wie ihr Computer es erlaubt) +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :Keine Beschränkung (so schnell wie Ihr Computer es erlaubt) STR_CONFIG_SETTING_ENABLE_BUILD_RIVER :Aktiviere das Bauen von Flüssen: {STRING} STR_CONFIG_SETTING_ENABLE_BUILD_RIVER_HELPTEXT :Aktiviere das Bauen von Flüssen außerhalb des Szenarioeditors -STR_CONFIG_SETTING_ENABLE_REMOVE_WATER :Aktiviere das entfernen von Meereskacheln und Flüssen: {STRING} -STR_CONFIG_SETTING_ENABLE_REMOVE_WATER_HELPTEXT :Aktiviere das entfernen von Meereskacheln und Flüssen außerhalb des Szenarioeditors +STR_CONFIG_SETTING_ENABLE_REMOVE_WATER :Aktiviere das Entfernen von Meereskacheln und Flüssen: {STRING} +STR_CONFIG_SETTING_ENABLE_REMOVE_WATER_HELPTEXT :Aktiviere das Entfernen von Meereskacheln und Flüssen außerhalb des Szenarioeditors STR_CONFIG_SETTING_SOUND_TICKER :Nachrichtenticker: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Soundeffekte für Kurzfassungen von Nachrichten abspielen (Ticker) From f047690dc92c1c2f670a31769c690c414ad75462 Mon Sep 17 00:00:00 2001 From: Woelfi Von Wolfhausen <65563631+WoelfiVW@users.noreply.github.com> Date: Sun, 26 Sep 2021 18:17:04 +0200 Subject: [PATCH 04/43] Fix typo, ii Typo, a t was missing (Frach-art to Fracht-art) --- src/lang/german.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/german.txt b/src/lang/german.txt index b4946432bd..69a087ab55 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1418,7 +1418,7 @@ STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES :Zeige erweitert STR_CONFIG_SETTING_SHOW_ADV_TRACE_RESTRICT_FEATURES_HELPTEXT :Zeige die erweiterten Features der Routing-Beschränkungen. Wenn inaktiv, werden einige erweiterte Features zwar nicht in der Oberfläche angezeigt, stehen aber dennoch allen Spielern zur Verfügung. STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES :Zeige programmierbares Einfahrtssignal-Feature: {STRING} STR_CONFIG_SETTING_SHOW_PROGSIG_FEATURES_HELPTEXT :Zeige das programmierbares Einfahrtssignal-Feature. Falls deaktiviert, werden die Bedienelemente zum Bau und zur Konfiguration von programmierbaren Einfahrtssignalen zwar nicht in der Oberfläche angezeigt, stehen aber dennoch allen Spielern zur Verfügung. -STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER :Zeige Filterung nach Frachart in Fahrzeuglisten: {STRING} +STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER :Zeige Filterung nach Frachtart in Fahrzeuglisten: {STRING} STR_CONFIG_SETTING_SHOW_VEH_LIST_CARGO_FILTER_HELPTEXT :Zeige die Filterung nach Frachtart in Fahrzeuglisten. Falls aktiviert, beinhalten die Fahrzeuglisten-Fenster eine weitere Filteroption. STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES :Zeige erweiterter Lademodus-Features: {STRING} STR_CONFIG_SETTING_SHOW_ADV_LOADING_MODE_FEATURES_HELPTEXT :Zeige erweiterter Lademodus-Features (durchgehendes Laden/Entladen). Falls deaktiviert, werden einige erweiterte Lademodus-Features zwar nicht in der Oberfläche angezeigt, stehen aber dennoch allen Spielern zur Verfügung. From 47156122fa42927e8d0cea289c2d71df50e63c2c Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 29 Sep 2021 19:13:22 +0100 Subject: [PATCH 05/43] Settings: Add a guiproc callback for general settings GUI operations --- src/settings.cpp | 4 ++ src/settings_gui.cpp | 28 +++++--- src/settings_internal.h | 11 +++ src/table/company_settings.ini | 5 +- src/table/currency_settings.ini | 5 +- src/table/gameopt_settings.ini | 13 ++-- src/table/misc_settings.ini | 15 +++-- src/table/settings.h.preamble | 114 ++++++++++++++++---------------- src/table/settings.ini | 31 ++++----- src/table/win32_settings.ini | 5 +- src/table/window_settings.ini | 5 +- 11 files changed, 134 insertions(+), 102 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 3ec5efe75c..da8c80c844 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1879,6 +1879,10 @@ static int64 LinkGraphDistModeXrefChillPP(int64 val) /* End - xref conversion callbacks */ +/* Begin - GUI callbacks */ + +/* End - GUI callbacks */ + /** * Prepare for reading and old diff_custom by zero-ing the memory. */ diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index d55448493f..50955726e0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -843,15 +843,7 @@ struct SettingEntry : BaseSettingEntry { virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible); void SetButtons(byte new_val); - - /** - * Get the help text of a single setting. - * @return The requested help text. - */ - inline StringID GetHelpText() const - { - return this->setting->desc.str_help; - } + StringID GetHelpText() const; struct SetValueDParamsTempData { char buffer[512]; @@ -868,6 +860,24 @@ private: bool IsVisibleByRestrictionMode(RestrictionMode mode) const; }; +/** + * Get the help text of a single setting. + * @return The requested help text. + */ +StringID SettingEntry::GetHelpText() const +{ + StringID str = this->setting->desc.str_help; + if (this->setting->desc.guiproc != nullptr) { + SettingOnGuiCtrlData data; + data.type = SOGCT_DESCRIPTION_TEXT; + data.text = str; + if (this->setting->desc.guiproc(data)) { + str = data.text; + } + } + return str; +} + /** Cargodist per-cargo setting */ struct CargoDestPerCargoSettingEntry : SettingEntry { CargoID cargo; diff --git a/src/settings_internal.h b/src/settings_internal.h index f0cd990519..2d6175ab61 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -89,9 +89,19 @@ enum SettingType { ST_ALL, ///< Used in setting filter to match all types. }; +enum SettingOnGuiCtrlType { + SOGCT_DESCRIPTION_TEXT, ///< Description text callback +}; + +struct SettingOnGuiCtrlData { + SettingOnGuiCtrlType type; + StringID text; +}; + typedef bool OnChange(int32 var); ///< callback prototype on data modification typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error typedef int OnGuiOrder(uint nth); ///< callback prototype for GUI ordering +typedef bool OnGuiCtrl(SettingOnGuiCtrlData &data); ///< callback prototype for GUI operations typedef int64 OnXrefValueConvert(int64 val); ///< callback prototype for xref value conversion /** The last entry in an array of struct SettingDescEnumEntry must use STR_NULL. */ @@ -114,6 +124,7 @@ struct SettingDescBase { StringID str_help; ///< (Translated) string with help text; gui only. StringID str_val; ///< (Translated) first string describing the value. OnChange *proc; ///< callback procedure for when the value is changed + OnGuiCtrl *guiproc; ///< callback procedure for GUI operations OnConvert *proc_cnvt; ///< callback procedure when loading value mechanism fails SettingCategory cat; ///< assigned categories of the setting bool startup; ///< setting has to be loaded directly at startup? diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index aaaa60f7fb..5dd9566d9f 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -16,8 +16,8 @@ static const SettingDesc _company_settings[] = { [post-amble] }; [templates] -SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_END = SDT_END() @@ -32,6 +32,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index 9dd65b7eb3..3aeab527b7 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -9,8 +9,8 @@ static const SettingDesc _currency_settings[] = { [post-amble] }; [templates] -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), -SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_END = SDT_END() [validation] @@ -24,6 +24,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 74b171d5c8..e866d0a3ea 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -37,13 +37,13 @@ static const SettingDesc _gameopt_settings[] = { [post-amble] }; [templates] -SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), SDT_NULL = SDT_NULL($length, $from, $to, $extver), -SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $startup, $extver, nullptr), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $load, $cat, $startup, $extver, nullptr), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), SDT_END = SDT_END() [validation] @@ -61,6 +61,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index eab963d0ee..40c47bfcab 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -20,13 +20,13 @@ static const SettingDescGlobVarList _misc_settings[] = { [post-amble] }; [templates] -SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), SDTG_END = SDTG_END() [validation] @@ -41,6 +41,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index 5bc12b7e9b..7cb1867d08 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -56,99 +56,99 @@ static size_t ConvertLandscape(const char *value); * on the appropriate macro. */ -#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, enumlist)\ - {name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, enumlist} +#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, guiproc, load, cat, startup, enumlist)\ + {name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, guiproc, load, cat, startup, enumlist} /* Macros for various objects to go in the configuration file. * This section is for global variables */ -#define SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, nullptr, cat, startup, enumlist), SLEG_GENERAL_X(sle_cmd, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} +#define SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ + {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, nullptr, cat, startup, enumlist), SLEG_GENERAL_X(sle_cmd, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} -#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, nullptr, nullptr) +#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, nullptr, nullptr) -#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc)\ - SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ + SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, nullptr) -#define SDTG_ENUM(name, type, flags, guiflags, var, def, str, strhelp, proc, from, to, cat, startup, extver, patxname, enumlist)\ - SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, var, 0, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) +#define SDTG_ENUM(name, type, flags, guiflags, var, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ + SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, var, 0, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) -#define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTG_SSTR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_SSTR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) #define SDTG_NULL(length, from, to, extver)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_NULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_NULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} -#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_END(), nullptr, SettingsXref(), nullptr} +#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_END(), nullptr, SettingsXref(), nullptr} /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ -#define SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat, startup, enumlist), SLE_GENERAL_X(sle_cmd, base, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} +#define SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ + {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, cat, startup, enumlist), SLE_GENERAL_X(sle_cmd, base, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} -#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, startup, extver, patxname, nullptr, nullptr) +#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, nullptr, nullptr) -#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc)\ - SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ + SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, orderproc, nullptr) -#define SDT_ENUM(base, var, type, flags, guiflags, def, str, strhelp, proc, from, to, cat, startup, extver, patxname, enumlist)\ - SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) +#define SDT_ENUM(base, var, type, flags, guiflags, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ + SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) -#define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) +#define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) -#define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) +#define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) -#define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) +#define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) -#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat, startup, extver, patxname) +#define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, guiproc, from, to, load, cat, startup, extver, patxname)\ + SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname) -#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) +#define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, guiproc, strhelp, strval, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) #define SDT_NULL(length, from, to, extver)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} -#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc)\ - SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ + SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, nullptr) -#define SDTC_ENUM(var, type, flags, guiflags, def, str, strhelp, proc, from, to, cat, startup, extver, patxname, enumlist)\ - SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, _settings_client.var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) +#define SDTC_ENUM(var, type, flags, guiflags, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ + SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, _settings_client.var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) -#define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, sizeof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, sizeof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) -#define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname) +#define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) #define SDT_XREF(from, to, extver, xref, xrefcvt)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(0, from, to, extver), nullptr, SettingsXref(xref, xrefcvt), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(0, from, to, extver), nullptr, SettingsXref(xref, xrefcvt), nullptr} -#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_END(), nullptr, SettingsXref(), nullptr} +#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_END(), nullptr, SettingsXref(), nullptr} diff --git a/src/table/settings.ini b/src/table/settings.ini index 659d22134d..b08753b928 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -142,25 +142,25 @@ const SettingDesc _settings[] = { [post-amble] }; [templates] -SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), -SDTG_ENUM = SDTG_ENUM($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $proc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), -SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), -SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $startup, $extver, $patxname), -SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), -SDT_ENUM = SDT_ENUM($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $proc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), +SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDTG_ENUM = SDTG_ENUM($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), +SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $load, $cat, $startup, $extver, $patxname), +SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDT_ENUM = SDT_ENUM($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_XREF = SDT_XREF( $from, $to, $extver, $xref, $xrefcvt), SDT_END = SDT_END() -SDT_LINKGRAPH_PER_CARGO = SDT_ENUM(GameSettings, linkgraph.distribution_per_cargo[$linkgraph_cargo], SLE_UINT8, $flags | SLF_NOT_IN_CONFIG, $guiflags | SGF_NO_NEWGAME, DT_PER_CARGO_DEFAULT, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT, $proc, $from, $to, SC_EXPERT, false, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_MODES), nullptr, _linkgraph_mode_per_cargo), +SDT_LINKGRAPH_PER_CARGO = SDT_ENUM(GameSettings, linkgraph.distribution_per_cargo[$linkgraph_cargo], SLE_UINT8, $flags | SLF_NOT_IN_CONFIG, $guiflags | SGF_NO_NEWGAME, DT_PER_CARGO_DEFAULT, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT, $proc, $guiproc, $from, $to, SC_EXPERT, false, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_MODES), nullptr, _linkgraph_mode_per_cargo), [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -178,6 +178,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini index c6c56516c5..ecc443fb95 100644 --- a/src/table/win32_settings.ini +++ b/src/table/win32_settings.ini @@ -14,8 +14,8 @@ static const SettingDescGlobVarList _win32_settings[] = { }; #endif /* _WIN32 */ [templates] -SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), SDTG_END = SDTG_END() [validation] @@ -29,6 +29,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini index bb20a1d21d..5d1e03973e 100644 --- a/src/table/window_settings.ini +++ b/src/table/window_settings.ini @@ -10,8 +10,8 @@ static const SettingDesc _window_settings[] = { [post-amble] }; [templates] -SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), SDT_END = SDT_END() [validation] @@ -26,6 +26,7 @@ str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = nullptr +guiproc = nullptr load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION From db11c1d927e225f2caa728548609e642d19d11f6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 29 Sep 2021 19:34:36 +0100 Subject: [PATCH 06/43] Add setting description help text for extra asymmetric linkgraph modes See also: #321 --- src/lang/english.txt | 1 + src/settings.cpp | 13 +++++++++++++ src/table/settings.ini | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 797fd7db60..36f75ff67e 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2061,6 +2061,7 @@ STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO :Distribution mo STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_PARAM :Distribution mode override for {STRING}: {STRING2} STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT :"(default)" means that the distribution mode is the default for the class of this cargo. "symmetric" means that roughly the same number of cargo will go from a station A to a station B as from B to A. "asymmetric" means that arbitrary amounts of cargo can be sent in either direction. "manual" means that no automatic distribution will take place for this cargo. STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_DEFAULT :(default) +STR_CONFIG_SETTING_DISTRIBUTION_HELPTEXT_EXTRA :{STRING}{}"asymmetric (equal distribution)" means that cargo will be distributed such that each accepting station receives approximately the same amount of cargo in total. "asymmetric (nearest)" means that cargo is sent to whichever accepting station is nearest. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distribution accuracy: {STRING2} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :The higher you set this the more CPU time the calculation of the link graph will take. If it takes too long you may notice lag. If you set it to a low value, however, the distribution will be inaccurate, and you may notice cargo not being sent to the places you expect it to go. STR_CONFIG_SETTING_DEMAND_DISTANCE :Effect of distance on demands: {STRING2} diff --git a/src/settings.cpp b/src/settings.cpp index da8c80c844..ca71b51a7d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1881,6 +1881,19 @@ static int64 LinkGraphDistModeXrefChillPP(int64 val) /* Begin - GUI callbacks */ +static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data) +{ + switch (data.type) { + case SOGCT_DESCRIPTION_TEXT: + SetDParam(0, data.text); + data.text = STR_CONFIG_SETTING_DISTRIBUTION_HELPTEXT_EXTRA; + return true; + + default: + return false; + } +} + /* End - GUI callbacks */ /** diff --git a/src/table/settings.ini b/src/table/settings.ini index b08753b928..38ab9196de 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -77,6 +77,8 @@ static bool CheckSharingRoad(int32 p1); static bool CheckSharingWater(int32 p1); static bool CheckSharingAir(int32 p1); +static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data); + /* End - Callback Functions for the various settings */ /* Begin - GUI order callbacks */ @@ -160,7 +162,7 @@ SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_XREF = SDT_XREF( $from, $to, $extver, $xref, $xrefcvt), SDT_END = SDT_END() -SDT_LINKGRAPH_PER_CARGO = SDT_ENUM(GameSettings, linkgraph.distribution_per_cargo[$linkgraph_cargo], SLE_UINT8, $flags | SLF_NOT_IN_CONFIG, $guiflags | SGF_NO_NEWGAME, DT_PER_CARGO_DEFAULT, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT, $proc, $guiproc, $from, $to, SC_EXPERT, false, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_MODES), nullptr, _linkgraph_mode_per_cargo), +SDT_LINKGRAPH_PER_CARGO = SDT_ENUM(GameSettings, linkgraph.distribution_per_cargo[$linkgraph_cargo], SLE_UINT8, $flags | SLF_NOT_IN_CONFIG, $guiflags | SGF_NO_NEWGAME, DT_PER_CARGO_DEFAULT, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT, $proc, LinkGraphDistributionSettingGUI, $from, $to, SC_EXPERT, false, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_MODES), nullptr, _linkgraph_mode_per_cargo), [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -1007,6 +1009,7 @@ def = DT_MANUAL enumlist = _linkgraph_mode_symmetric str = STR_CONFIG_SETTING_DISTRIBUTION_PAX strhelp = STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT +guiproc = LinkGraphDistributionSettingGUI [SDT_ENUM] base = GameSettings @@ -1017,6 +1020,7 @@ def = DT_MANUAL enumlist = _linkgraph_mode_symmetric str = STR_CONFIG_SETTING_DISTRIBUTION_MAIL strhelp = STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT +guiproc = LinkGraphDistributionSettingGUI [SDT_ENUM] base = GameSettings @@ -1027,6 +1031,7 @@ def = DT_MANUAL enumlist = _linkgraph_mode_symmetric str = STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED strhelp = STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT +guiproc = LinkGraphDistributionSettingGUI [SDT_ENUM] base = GameSettings @@ -1037,6 +1042,7 @@ def = DT_MANUAL enumlist = _linkgraph_mode_asymmetric str = STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT strhelp = STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT +guiproc = LinkGraphDistributionSettingGUI [SDT_LINKGRAPH_PER_CARGO] linkgraph_cargo = 0 From 65c20edde740a37128b8450767655798ee48fa64 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 29 Sep 2021 20:10:38 +0100 Subject: [PATCH 07/43] Settings: Merge orderproc into guiproc --- src/settings.cpp | 37 +++++++++++++++++------------- src/settings_gui.cpp | 10 ++++++++- src/settings_internal.h | 4 ++-- src/table/company_settings.ini | 3 +-- src/table/currency_settings.ini | 3 +-- src/table/gameopt_settings.ini | 5 ++--- src/table/misc_settings.ini | 3 +-- src/table/settings.h.preamble | 40 ++++++++++++++++----------------- src/table/settings.ini | 24 +++++++++----------- src/table/win32_settings.ini | 3 +-- src/table/window_settings.ini | 3 +-- 11 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index ca71b51a7d..d80a78581b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1855,21 +1855,6 @@ static bool UpdateClientConfigValues(int32 p1) /* End - Callback Functions */ -/* Begin - GUI order callbacks */ - -static int OrderTownGrowthRate(uint nth) -{ - if (nth == 0) { - return 0; - } else if (nth <= 2) { - return nth - 3; - } else { - return nth - 2; - } -} - -/* End - GUI order callbacks */ - /* Begin - xref conversion callbacks */ static int64 LinkGraphDistModeXrefChillPP(int64 val) @@ -1881,6 +1866,28 @@ static int64 LinkGraphDistModeXrefChillPP(int64 val) /* Begin - GUI callbacks */ +static bool OrderTownGrowthRate(SettingOnGuiCtrlData &data) +{ + switch (data.type) { + case SOGCT_MULTISTRING_ORDER: { + int in = data.val; + int out; + if (in == 0) { + out = 0; + } else if (in <= 2) { + out = in - 3; + } else { + out = in - 2; + } + data.val = out; + return true; + } + + default: + return false; + } +} + static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data) { switch (data.type) { diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 50955726e0..248f9216c1 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2578,7 +2578,15 @@ struct GameSettingsWindow : Window { DropDownList list; if (sd->desc.flags & SGF_MULTISTRING) { for (int i = sdb->min; i <= (int)sdb->max; i++) { - int val = sd->orderproc ? sd->orderproc(i - sdb->min) : i; + int val = i; + if (sd->desc.guiproc != nullptr) { + SettingOnGuiCtrlData data; + data.type = SOGCT_MULTISTRING_ORDER; + data.val = i - sdb->min; + if (sd->desc.guiproc(data)) { + val = data.val; + } + } assert_msg(val >= sdb->min && val <= (int)sdb->max, "min: %d, max: %d, val: %d", sdb->min, sdb->max, val); list.emplace_back(new DropDownListStringItem(sdb->str_val + val - sdb->min, val, false)); } diff --git a/src/settings_internal.h b/src/settings_internal.h index 2d6175ab61..fd08666828 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -91,16 +91,17 @@ enum SettingType { enum SettingOnGuiCtrlType { SOGCT_DESCRIPTION_TEXT, ///< Description text callback + SOGCT_MULTISTRING_ORDER, ///< SGF_MULTISTRING reordering callback }; struct SettingOnGuiCtrlData { SettingOnGuiCtrlType type; StringID text; + int val; }; typedef bool OnChange(int32 var); ///< callback prototype on data modification typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error -typedef int OnGuiOrder(uint nth); ///< callback prototype for GUI ordering typedef bool OnGuiCtrl(SettingOnGuiCtrlData &data); ///< callback prototype for GUI operations typedef int64 OnXrefValueConvert(int64 val); ///< callback prototype for xref value conversion @@ -144,7 +145,6 @@ struct SettingDesc { SaveLoad save; ///< Internal structure (going to savegame, parts to config) const char *patx_name; ///< Name to save/load setting from in PATX chunk, if nullptr save/load from PATS chunk as normal SettingsXref xref; ///< Details of SettingDesc to use instead of the contents of this one, useful for loading legacy savegames, if target field nullptr save/load as normal - OnGuiOrder *orderproc; ///< Callback procedure for GUI re-ordering bool IsEditable(bool do_command = false) const; SettingType GetType() const; diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index 5dd9566d9f..62503309c5 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -17,7 +17,7 @@ static const SettingDesc _company_settings[] = { }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_END = SDT_END() @@ -40,7 +40,6 @@ cat = SC_ADVANCED startup = false extver = SlXvFeatureTest() patxname = nullptr -orderproc = nullptr diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index 3aeab527b7..683fae40ae 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -9,7 +9,7 @@ static const SettingDesc _currency_settings[] = { [post-amble] }; [templates] -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_END = SDT_END() @@ -31,7 +31,6 @@ to = SL_MAX_VERSION cat = SC_ADVANCED startup = false extver = SlXvFeatureTest() -orderproc = nullptr diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index e866d0a3ea..3093ecc69c 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -38,12 +38,12 @@ static const SettingDesc _gameopt_settings[] = { }; [templates] SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $load, $cat, $startup, $extver, nullptr), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_END = SDT_END() [validation] @@ -68,7 +68,6 @@ to = SL_MAX_VERSION cat = SC_ADVANCED startup = false extver = SlXvFeatureTest() -orderproc = nullptr diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 40c47bfcab..0a80183e9a 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -26,7 +26,7 @@ SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_END = SDTG_END() [validation] @@ -48,7 +48,6 @@ to = SL_MAX_VERSION cat = SC_ADVANCED startup = true extver = SlXvFeatureTest() -orderproc = nullptr diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index 7cb1867d08..30ac7f064d 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -61,17 +61,17 @@ static size_t ConvertLandscape(const char *value); /* Macros for various objects to go in the configuration file. * This section is for global variables */ -#define SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, nullptr, cat, startup, enumlist), SLEG_GENERAL_X(sle_cmd, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} +#define SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ + {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, nullptr, cat, startup, enumlist), SLEG_GENERAL_X(sle_cmd, var, type | flags, length, from, to, extver), patxname, SettingsXref()} #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ - SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, nullptr, nullptr) + SDTG_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, nullptr) -#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ - SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, nullptr) #define SDTG_ENUM(name, type, flags, guiflags, var, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ - SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, var, 0, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) + SDTG_GENERAL2(name, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, var, 0, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, enumlist) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) @@ -92,23 +92,23 @@ static size_t ConvertLandscape(const char *value); SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) #define SDTG_NULL(length, from, to, extver)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_NULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_NULL_X(length, from, to, extver), nullptr, SettingsXref()} -#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_END(), nullptr, SettingsXref(), nullptr} +#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLEG_END(), nullptr, SettingsXref()} /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ -#define SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, orderproc, enumlist)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, cat, startup, enumlist), SLE_GENERAL_X(sle_cmd, base, var, type | flags, length, from, to, extver), patxname, SettingsXref(), orderproc} +#define SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, enumlist)\ + {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, cat, startup, enumlist), SLE_GENERAL_X(sle_cmd, base, var, type | flags, length, from, to, extver), patxname, SettingsXref()} #define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, nullptr, nullptr) + SDT_GENERAL2(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, guiproc, load, from, to, cat, startup, extver, patxname, nullptr) -#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ - SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr) #define SDT_ENUM(base, var, type, flags, guiflags, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ - SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) + SDT_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, enumlist) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) @@ -126,14 +126,14 @@ static size_t ConvertLandscape(const char *value); SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname) #define SDT_NULL(length, from, to, extver)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(length, from, to, extver), nullptr, SettingsXref(), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(length, from, to, extver), nullptr, SettingsXref()} -#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc)\ - SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, orderproc, nullptr) +#define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ + SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname, nullptr) #define SDTC_ENUM(var, type, flags, guiflags, def, str, strhelp, proc, guiproc, from, to, cat, startup, extver, patxname, enumlist)\ - SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, _settings_client.var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname, nullptr, enumlist) + SDTG_GENERAL2(#var, SDT_NUMX, SL_VAR, type, flags, guiflags | SGF_ENUM, _settings_client.var, 1, def, 0, 0, 0, nullptr, str, strhelp, STR_NULL, proc, guiproc, nullptr, from, to, cat, startup, extver, patxname,, enumlist) #define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname)\ SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) @@ -148,7 +148,7 @@ static size_t ConvertLandscape(const char *value); SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, guiproc, from, to, cat, startup, extver, patxname) #define SDT_XREF(from, to, extver, xref, xrefcvt)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(0, from, to, extver), nullptr, SettingsXref(xref, xrefcvt), nullptr} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_CONDNULL_X(0, from, to, extver), nullptr, SettingsXref(xref, xrefcvt)} -#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_END(), nullptr, SettingsXref(), nullptr} +#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, nullptr, SC_NONE, false, nullptr}, SLE_END(), nullptr, SettingsXref()} diff --git a/src/table/settings.ini b/src/table/settings.ini index 38ab9196de..13c19b490d 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -77,22 +77,21 @@ static bool CheckSharingRoad(int32 p1); static bool CheckSharingWater(int32 p1); static bool CheckSharingAir(int32 p1); -static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data); - /* End - Callback Functions for the various settings */ -/* Begin - GUI order callbacks */ - -static int OrderTownGrowthRate(uint nth); - -/* End - GUI order callbacks */ - /* Begin - xref conversion callbacks */ static int64 LinkGraphDistModeXrefChillPP(int64 val); /* End - xref conversion callbacks */ +/* Begin - GUI callbacks */ + +static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data); +static bool OrderTownGrowthRate(SettingOnGuiCtrlData &data); + +/* End - GUI callbacks */ + static const SettingDescEnumEntry _linkgraph_mode_symmetric[] = { { DT_MANUAL, STR_CONFIG_SETTING_DISTRIBUTION_MANUAL }, { DT_SYMMETRIC, STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC }, @@ -145,18 +144,18 @@ const SettingDesc _settings[] = { }; [templates] SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDTG_ENUM = SDTG_ENUM($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), -SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $load, $cat, $startup, $extver, $patxname), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $orderproc), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname), SDT_ENUM = SDT_ENUM($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $proc, $guiproc, $from, $to, $cat, $startup, $extver, $patxname, $enumlist), SDT_NULL = SDT_NULL($length, $from, $to, $extver), SDT_XREF = SDT_XREF( $from, $to, $extver, $xref, $xrefcvt), @@ -190,7 +189,6 @@ extver = SlXvFeatureTest() patxname = nullptr xref = xrefcvt = nullptr -orderproc = nullptr enumlist = @@ -2505,7 +2503,7 @@ max = 4 str = STR_CONFIG_SETTING_TOWN_GROWTH strhelp = STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT strval = STR_CONFIG_SETTING_TOWN_GROWTH_EXTREME_SLOW -orderproc = OrderTownGrowthRate +guiproc = OrderTownGrowthRate [SDT_BOOL] base = GameSettings diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini index ecc443fb95..86d582c1b3 100644 --- a/src/table/win32_settings.ini +++ b/src/table/win32_settings.ini @@ -15,7 +15,7 @@ static const SettingDescGlobVarList _win32_settings[] = { #endif /* _WIN32 */ [templates] SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDTG_END = SDTG_END() [validation] @@ -36,7 +36,6 @@ to = SL_MAX_VERSION cat = SC_ADVANCED startup = true extver = SlXvFeatureTest() -orderproc = nullptr [SDTG_BOOL] diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini index 5d1e03973e..573986aeb3 100644 --- a/src/table/window_settings.ini +++ b/src/table/window_settings.ini @@ -11,7 +11,7 @@ static const SettingDesc _window_settings[] = { }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), -SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), +SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $guiproc, $from, $to, $cat, $startup, $extver, nullptr), SDT_END = SDT_END() [validation] @@ -33,7 +33,6 @@ to = SL_MAX_VERSION cat = SC_ADVANCED startup = false extver = SlXvFeatureTest() -orderproc = nullptr From 513f6db718fa05a7caf02b4bb500e1a2058eb301 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 30 Sep 2021 18:42:51 +0100 Subject: [PATCH 08/43] Increase command log ring buffer size to 256 --- src/command.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index e0c9cb0242..e05765602c 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -554,7 +554,7 @@ struct CommandLogEntry { }; struct CommandLog { - std::array log; + std::array log; unsigned int count = 0; unsigned int next = 0; @@ -619,7 +619,7 @@ static void DumpSubCommandLog(char *&buffer, const char *last, const CommandLog char *DumpCommandLog(char *buffer, const char *last) { - const unsigned int count = std::min(_command_log.count, 128); + const unsigned int count = std::min(_command_log.count, 256); buffer += seprintf(buffer, last, "Command Log:\n Showing most recent %u of %u commands\n", count, _command_log.count); DumpSubCommandLog(buffer, last, _command_log, count); From 2df744db79e5ea45decb15ce454d1587bab7d118 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 2 Oct 2021 11:54:59 +0100 Subject: [PATCH 09/43] OSX: Fix CoreTextFontCache not setting font_height_cache See: #323 --- src/os/macosx/font_osx.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index f5ceed8507..1ceeaa89a0 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -215,6 +215,8 @@ void CoreTextFontCache::SetFontSize(int pixels) this->descender = -(int)std::ceil(CTFontGetDescent(this->font.get())); this->height = this->ascender - this->descender; + font_height_cache[this->fs] = this->GetHeight(); + /* Get real font name. */ char name[128]; CFAutoRelease font_name((CFStringRef)CTFontCopyAttribute(this->font.get(), kCTFontDisplayNameAttribute)); From c47fd3033066d0a7aec96ea9040f81730a0cca42 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 2 Oct 2021 21:24:56 +0100 Subject: [PATCH 10/43] Include docking tiles in station debug window --- src/table/newgrf_debug_data.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 7d7156d9b9..5fa8c129e5 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -1149,6 +1149,8 @@ class NIHStationStruct : public NIHelper { print(buffer); seprintf(buffer, lastof(buffer), " Delete counter: %u", st->delete_ctr); print(buffer); + seprintf(buffer, lastof(buffer), " Docking tiles: %X, %u x %u", st->docking_station.tile, st->docking_station.w, st->docking_station.h); + print(buffer); } } }; From 96ea775b24a31168b3341ef7e83ec20dba3acd75 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 2 Oct 2021 16:45:02 +0100 Subject: [PATCH 11/43] Avoid undefined behaviour in saveload chunk handlers Use data() instead of &[0] to avoid issues with empty vectors --- src/saveload/bridge_signal_sl.cpp | 4 ++-- src/saveload/plans_sl.cpp | 6 +++--- src/saveload/tracerestrict_sl.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/saveload/bridge_signal_sl.cpp b/src/saveload/bridge_signal_sl.cpp index 596194d2f3..4c73478527 100644 --- a/src/saveload/bridge_signal_sl.cpp +++ b/src/saveload/bridge_signal_sl.cpp @@ -30,7 +30,7 @@ static void Load_XBSS() 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[0]), stub.length, SLE_UINT64); + SlArray(lbss.signal_red_bits.data(), stub.length, SLE_UINT64); } } @@ -39,7 +39,7 @@ static void RealSave_XBSS(const LongBridgeSignalStorage *lbss) LongBridgeSignalStorageStub stub; stub.length = (uint32)lbss->signal_red_bits.size(); SlObject(&stub, _long_bridge_signal_storage_stub_desc); - SlArray(const_cast(&(lbss->signal_red_bits[0])), stub.length, SLE_UINT64); + SlArray(const_cast(lbss->signal_red_bits.data()), stub.length, SLE_UINT64); } static void Save_XBSS() diff --git a/src/saveload/plans_sl.cpp b/src/saveload/plans_sl.cpp index a7e33d90fb..94c2e80b8d 100644 --- a/src/saveload/plans_sl.cpp +++ b/src/saveload/plans_sl.cpp @@ -32,7 +32,7 @@ static void RealSave_PLAN(Plan *p) for (size_t i = 0; i < p->lines.size(); i++) { PlanLine *pl = p->lines[i]; SlWriteUint32((uint32)pl->tiles.size()); - SlArray(&pl->tiles[0], pl->tiles.size(), SLE_UINT32); + SlArray(pl->tiles.data(), pl->tiles.size(), SLE_UINT32); } } @@ -60,7 +60,7 @@ static void Load_PLAN() p->lines[i] = pl; const size_t tile_count = SlReadUint32(); pl->tiles.resize(tile_count); - SlArray(&pl->tiles[0], tile_count, SLE_UINT32); + SlArray(pl->tiles.data(), tile_count, SLE_UINT32); pl->UpdateVisualExtents(); } p->SetVisibility(false); @@ -80,7 +80,7 @@ static void Load_PLANLINE() p->lines[line_index] = pl; size_t plsz = SlGetFieldLength() / sizeof(TileIndex); pl->tiles.resize(plsz); - SlArray(&pl->tiles[0], plsz, SLE_UINT32); + SlArray(pl->tiles.data(), plsz, SLE_UINT32); pl->UpdateVisualExtents(); } diff --git a/src/saveload/tracerestrict_sl.cpp b/src/saveload/tracerestrict_sl.cpp index e8fcaee444..53f9eb23f2 100644 --- a/src/saveload/tracerestrict_sl.cpp +++ b/src/saveload/tracerestrict_sl.cpp @@ -64,7 +64,7 @@ static void Load_TRRP() TraceRestrictProgram *prog = new (index) TraceRestrictProgram(); SlObject(&stub, _trace_restrict_program_stub_desc); prog->items.resize(stub.length); - SlArray(&(prog->items[0]), stub.length, SLE_UINT32); + if (stub.length > 0) SlArray(prog->items.data(), stub.length, SLE_UINT32); if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) { for (size_t i = 0; i < prog->items.size(); i++) { TraceRestrictItem &item = prog->items[i]; // note this is a reference, @@ -99,7 +99,7 @@ static void RealSave_TRRP(TraceRestrictProgram *prog) TraceRestrictProgramStub stub; stub.length = (uint32)prog->items.size(); SlObject(&stub, _trace_restrict_program_stub_desc); - SlArray(&(prog->items[0]), stub.length, SLE_UINT32); + SlArray(prog->items.data(), stub.length, SLE_UINT32); } /** @@ -142,7 +142,7 @@ static void Load_TRRS() SlObject(slot, _trace_restrict_slot_desc); SlObject(&stub, _trace_restrict_slot_stub_desc); slot->occupants.resize(stub.length); - if (stub.length) SlArray(&(slot->occupants[0]), stub.length, SLE_UINT32); + if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); } TraceRestrictSlot::RebuildVehicleIndex(); } @@ -156,7 +156,7 @@ static void RealSave_TRRS(TraceRestrictSlot *slot) TraceRestrictSlotStub stub; stub.length = (uint32)slot->occupants.size(); SlObject(&stub, _trace_restrict_slot_stub_desc); - if (stub.length) SlArray(&(slot->occupants[0]), stub.length, SLE_UINT32); + if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); } /** From d4d54c9b902b3eb5351bc9fdf9b95ee7683d24d0 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 01:58:54 +0100 Subject: [PATCH 12/43] Add a chicken bit setting to enable periodic CheckCaches --- src/debug_settings.h | 1 + src/openttd.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/debug_settings.h b/src/debug_settings.h index a31b3833c4..cc031e2756 100644 --- a/src/debug_settings.h +++ b/src/debug_settings.h @@ -16,6 +16,7 @@ enum ChickenBitFlags { DCBF_VEH_TICK_CACHE = 0, DCBF_MP_NO_STATE_CSUM_CHECK = 1, + DCBF_DESYNC_CHECK_PERIODIC = 2, }; inline bool HasChickenBit(ChickenBitFlags flag) diff --git a/src/openttd.cpp b/src/openttd.cpp index 690e5efe43..c3ae283e5c 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -78,6 +78,7 @@ #include "cargopacket.h" #include "core/checksum_func.hpp" #include "tbtr_template_vehicle_func.h" +#include "debug_settings.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -1360,11 +1361,15 @@ void WriteVehicleInfo(char *&p, const char *last, const Vehicle *u, const Vehicl void CheckCaches(bool force_check, std::function log) { if (!force_check) { + int desync_level = _debug_desync_level; + + if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_PERIODIC)) && desync_level < 1) desync_level = 1; + /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ - if (_debug_desync_level < 1) return; + if (desync_level < 1) return; - if (_debug_desync_level == 1 && _scaled_date_ticks % 500 != 0) return; + if (desync_level == 1 && _scaled_date_ticks % 500 != 0) return; } char cclog_buffer[1024]; From 8f2582e0ff81009a2ead846499865edb4c4b896b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 02:17:52 +0100 Subject: [PATCH 13/43] Update help text for check_caches console command --- src/console_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 5f100df78a..74b47a945b 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2677,7 +2677,7 @@ DEF_CONSOLE_CMD(ConDumpTile) DEF_CONSOLE_CMD(ConCheckCaches) { if (argc == 0) { - IConsoleHelp("Debug: Check caches"); + IConsoleHelp("Debug: Check caches. Usage: 'check_caches []'"); return true; } From c99eaf72b79abbf5a8a148f51a5555a7c7d38132 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 15:06:58 +0100 Subject: [PATCH 14/43] Fix #9591: Update station docking tiles upon placing a water object on a docking tile (#9594) See: https://github.com/OpenTTD/OpenTTD/issues/9591 See: https://github.com/OpenTTD/OpenTTD/pull/9594 Non-extended savegame bump to be applied later (cherry picked from commit e404d16929991d1eddd9d37b859d3813be7e18ed) # Conflicts: # src/object_cmd.cpp # src/saveload/afterload.cpp # src/saveload/saveload.h --- src/object_cmd.cpp | 3 +++ src/saveload/afterload.cpp | 2 +- src/saveload/extended_ver_sl.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 299c92407b..f8fd241632 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -32,6 +32,7 @@ #include "date_func.h" #include "newgrf_debug.h" #include "vehicle_func.h" +#include "station_func.h" #include "table/strings.h" #include "table/object_land.h" @@ -122,7 +123,9 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u Company::Get(owner)->infrastructure.water++; DirtyCompanyInfrastructureWindows(owner); } + bool remove = IsDockingTile(t); MakeObject(t, owner, o->index, wc, Random()); + if (remove) RemoveDockingTile(t); MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE); } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 706b16ff7e..f03f999a21 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3743,7 +3743,7 @@ bool AfterLoadGame() } } - if (IsSavegameVersionUntil(SLV_ENDING_YEAR) || !SlXvIsFeaturePresent(XSLFI_MULTIPLE_DOCKS, 2) || !SlXvIsFeaturePresent(XSLFI_DOCKING_CACHE_VER, 1)) { + if (IsSavegameVersionUntil(SLV_ENDING_YEAR) || !SlXvIsFeaturePresent(XSLFI_MULTIPLE_DOCKS, 2) || !SlXvIsFeaturePresent(XSLFI_DOCKING_CACHE_VER, 2)) { /* Update station docking tiles. Was only needed for pre-SLV_MULTITLE_DOCKS * savegames, but a bug in docking tiles touched all savegames between * SLV_MULTITILE_DOCKS and SLV_ENDING_YEAR. */ diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index ae53343536..863d80c960 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -131,7 +131,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { 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 }, - { XSLFI_DOCKING_CACHE_VER, XSCF_IGNORABLE_ALL, 1, 1, "docking_cache_ver", nullptr, nullptr, nullptr }, + { XSLFI_DOCKING_CACHE_VER, XSCF_IGNORABLE_ALL, 2, 2, "docking_cache_ver", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_CHEATS, XSCF_NULL, 1, 1, "extra_cheats", nullptr, nullptr, "CHTX" }, { 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 }, From f5561ac2123fcd76548bb1a407f01983ef82cc40 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 19 Sep 2021 21:52:08 +0100 Subject: [PATCH 15/43] Fix #9562: Handle case of invalid action2 with zero results. (#9564) (cherry picked from commit 7e70ead39629c557c4580d1d66be0cdcc37480ec) --- src/newgrf.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 5454819845..19a374002e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5378,6 +5378,11 @@ static void NewSpriteGroup(ByteReader *buf) return; } + if (num_loaded + num_loading == 0) { + grfmsg(1, "NewSpriteGroup: no result, skipping invalid RealSpriteGroup"); + break; + } + assert(RealSpriteGroup::CanAllocateItem()); RealSpriteGroup *group = new RealSpriteGroup(); group->nfo_line = _cur.nfo_line; From cd97ca95f273adb84738c3cb634eac7f1d482d92 Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Thu, 23 Sep 2021 15:07:54 -0400 Subject: [PATCH 16/43] Fix: Changing raw industry funding method redraws GUI (#9572) (cherry picked from commit 4aa63ce8f3796fe85eda5ad4f0bf4b0eb5bea1ef) --- src/industry_gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 9d91de9080..1148e1acd6 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -769,6 +769,7 @@ public: const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? nullptr : GetIndustrySpec(this->selected_type); if (indsp == nullptr) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; this->SetButtons(); + this->SetDirty(); } }; From ff67f7b311cfa41b068b8f4edae9548a0da05d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Sat, 2 Oct 2021 15:13:58 +0200 Subject: [PATCH 17/43] Fix #9588, 140a96b: [Squirrel] Reaching memory limit during script registration could prevent further script detections (#9589) Also the memory allocation triggering the limit was never freed. And if the exception was thrown in a constructor using placement new, the pre-allocated memory was not freed either. (cherry picked from commit ccd586a736595c2af09c6f614c11a75b9b3da156) --- src/3rdparty/squirrel/squirrel/sqobject.h | 18 ++++++++++++++++++ src/script/squirrel.cpp | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/3rdparty/squirrel/squirrel/sqobject.h b/src/3rdparty/squirrel/squirrel/sqobject.h index 9212766eef..84880d9b86 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.h +++ b/src/3rdparty/squirrel/squirrel/sqobject.h @@ -62,6 +62,24 @@ struct SQRefCounted SQUnsignedInteger _uiRef; struct SQWeakRef *_weakref; virtual void Release()=0; + + /* Placement new/delete to prevent memory leaks if constructor throws an exception. */ + inline void *operator new(size_t size, SQRefCounted *place) + { + place->size = size; + return place; + } + + inline void operator delete(void *ptr, SQRefCounted *place) + { + SQ_FREE(ptr, place->size); + } + + /* Never used but required. */ + inline void operator delete(void *ptr) { NOT_REACHED(); } + +private: + size_t size; }; struct SQWeakRef : SQRefCounted diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 7fd5bef601..b9c9282c64 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -67,7 +67,7 @@ struct ScriptAllocator { * @param requested_size The requested size that was requested to be allocated. * @param p The pointer to the allocated object, or null if allocation failed. */ - void CheckAllocation(size_t requested_size, const void *p) + void CheckAllocation(size_t requested_size, void *p) { if (this->allocated_size > this->allocation_limit && !this->error_thrown) { /* Do not allow allocating more than the allocation limit, except when an error is @@ -77,6 +77,11 @@ struct ScriptAllocator { char buff[128]; seprintf(buff, lastof(buff), "Maximum memory allocation exceeded by " PRINTF_SIZE " bytes when allocating " PRINTF_SIZE " bytes", this->allocated_size - this->allocation_limit, requested_size); + /* Don't leak the rejected allocation. */ + free(p); + p = nullptr; + /* Allocation rejected, don't count it. */ + this->allocated_size -= requested_size; throw Script_FatalError(buff); } @@ -93,6 +98,8 @@ struct ScriptAllocator { this->error_thrown = true; char buff[64]; seprintf(buff, lastof(buff), "Out of memory. Cannot allocate " PRINTF_SIZE " bytes", requested_size); + /* Allocation failed, don't count it. */ + this->allocated_size -= requested_size; throw Script_FatalError(buff); } } @@ -765,6 +772,11 @@ void Squirrel::Uninitialize() /* Clean up the stuff */ sq_pop(this->vm, 1); sq_close(this->vm); + + assert(this->allocator->allocated_size == 0); + + /* Reset memory allocation errors. */ + this->allocator->error_thrown = false; } void Squirrel::Reset() From c4080075753fe551febd05cc01638dbd4656908f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Sat, 2 Oct 2021 21:08:42 +0200 Subject: [PATCH 18/43] Fix #9548, e5fedcd: [Squirrel] Crash during engine cleanup after reaching memory limit on realloc (#9592) (cherry picked from commit a53cfeef131fab66dc4a2395279b64706c5afed9) --- src/script/squirrel.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index b9c9282c64..76e60a66eb 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -69,19 +69,16 @@ struct ScriptAllocator { */ void CheckAllocation(size_t requested_size, void *p) { - if (this->allocated_size > this->allocation_limit && !this->error_thrown) { + if (this->allocated_size + requested_size > this->allocation_limit && !this->error_thrown) { /* Do not allow allocating more than the allocation limit, except when an error is * already as then the allocation is for throwing that error in Squirrel, the * associated stack trace information and while cleaning up the AI. */ this->error_thrown = true; char buff[128]; seprintf(buff, lastof(buff), "Maximum memory allocation exceeded by " PRINTF_SIZE " bytes when allocating " PRINTF_SIZE " bytes", - this->allocated_size - this->allocation_limit, requested_size); + this->allocated_size + requested_size - this->allocation_limit, requested_size); /* Don't leak the rejected allocation. */ free(p); - p = nullptr; - /* Allocation rejected, don't count it. */ - this->allocated_size -= requested_size; throw Script_FatalError(buff); } @@ -98,8 +95,6 @@ struct ScriptAllocator { this->error_thrown = true; char buff[64]; seprintf(buff, lastof(buff), "Out of memory. Cannot allocate " PRINTF_SIZE " bytes", requested_size); - /* Allocation failed, don't count it. */ - this->allocated_size -= requested_size; throw Script_FatalError(buff); } } @@ -107,10 +102,11 @@ struct ScriptAllocator { void *Malloc(SQUnsignedInteger size) { void *p = malloc(size); - this->allocated_size += size; this->CheckAllocation(size, p); + this->allocated_size += size; + #ifdef SCRIPT_DEBUG_ALLOCATIONS assert(p != nullptr); assert(this->allocations.find(p) == this->allocations.end()); @@ -134,14 +130,21 @@ struct ScriptAllocator { assert(this->allocations[p] == oldsize); this->allocations.erase(p); #endif + /* Can't use realloc directly because memory limit check. + * If memory exception is thrown, the old pointer is expected + * to be valid for engine cleanup. + */ + void *new_p = malloc(size); - void *new_p = realloc(p, size); + this->CheckAllocation(size - oldsize, new_p); + + /* Memory limit test passed, we can copy data and free old pointer. */ + memcpy(new_p, p, std::min(oldsize, size)); + free(p); this->allocated_size -= oldsize; this->allocated_size += size; - this->CheckAllocation(size, p); - #ifdef SCRIPT_DEBUG_ALLOCATIONS assert(new_p != nullptr); assert(this->allocations.find(p) == this->allocations.end()); From 5ed7aee8d3c63d6001a1ebf2eb993778d2a49031 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 23:03:26 +0100 Subject: [PATCH 19/43] Add flags field to CheckCaches for which checks to run Add header file for CheckCaches --- src/CMakeLists.txt | 1 + src/company_cmd.cpp | 2 +- src/console_cmds.cpp | 2 +- src/crashlog.cpp | 2 +- src/debug_desync.h | 25 ++ src/economy.cpp | 2 +- src/openttd.cpp | 635 ++++++++++++++++++++++--------------------- 7 files changed, 351 insertions(+), 318 deletions(-) create mode 100644 src/debug_desync.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8022223ed3..c3ef71917a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,6 +118,7 @@ add_files( date_type.h debug.cpp debug.h + debug_desync.h debug_settings.h dedicated.cpp departures.cpp diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 51bc4f95cf..965816ec3e 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -37,6 +37,7 @@ #include "zoning.h" #include "tbtr_template_vehicle_func.h" #include "widgets/statusbar_widget.h" +#include "debug_desync.h" #include "table/strings.h" @@ -937,7 +938,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0); - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); break; } diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 74b47a945b..4cec71eae2 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -53,6 +53,7 @@ #include "linkgraph/linkgraphjob.h" #include "base_media_base.h" #include "debug_settings.h" +#include "debug_desync.h" #include #include "safeguards.h" @@ -2687,7 +2688,6 @@ DEF_CONSOLE_CMD(ConCheckCaches) if (broadcast) { DoCommandP(0, 0, 0, CMD_DESYNC_CHECK); } else { - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); } diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 16ae1245e5..0fbd23ea91 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -30,6 +30,7 @@ #include "scope_info.h" #include "command_func.h" #include "thread.h" +#include "debug_desync.h" #include "ai/ai_info.hpp" #include "game/game.hpp" @@ -522,7 +523,6 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last, const DesyncE buffer = DumpDesyncMsgLog(buffer, last); bool have_cache_log = false; - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, [&](const char *str) { if (!have_cache_log) buffer += seprintf(buffer, last, "CheckCaches:\n"); buffer += seprintf(buffer, last, " %s\n", str); diff --git a/src/debug_desync.h b/src/debug_desync.h new file mode 100644 index 0000000000..98b8760f00 --- /dev/null +++ b/src/debug_desync.h @@ -0,0 +1,25 @@ +/* + * 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 debug_desync.h Desync debugging. */ + +#ifndef DEBUG_DESYNC_H +#define DEBUG_DESYNC_H + +#include + +enum CheckCachesFlags : uint32 { + CHECK_CACHE_NONE = 0, + CHECK_CACHE_GENERAL = 1 << 0, + CHECK_CACHE_INFRA_TOTALS = 1 << 1, + CHECK_CACHE_ALL = UINT32_MAX, +}; +DECLARE_ENUM_AS_BIT_SET(CheckCachesFlags) + +extern void CheckCaches(bool force_check, std::function log = nullptr, CheckCachesFlags flags = CHECK_CACHE_ALL); + +#endif /* DEBUG_DESYNC_H */ diff --git a/src/economy.cpp b/src/economy.cpp index f8c6a0afe6..6098f835ae 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -54,6 +54,7 @@ #include "tbtr_template_vehicle_func.h" #include "scope_info.h" #include "pathfinder/yapf/yapf_cache.h" +#include "debug_desync.h" #include "table/strings.h" #include "table/pricebase.h" @@ -2287,7 +2288,6 @@ static void DoAcquireCompany(Company *c) delete c; - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); } diff --git a/src/openttd.cpp b/src/openttd.cpp index c3ae283e5c..0cb3d7221f 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -79,6 +79,7 @@ #include "core/checksum_func.hpp" #include "tbtr_template_vehicle_func.h" #include "debug_settings.h" +#include "debug_desync.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -1358,7 +1359,7 @@ void WriteVehicleInfo(char *&p, const char *last, const Vehicle *u, const Vehicl * the cached value and what the value would * be when calculated from the 'base' data. */ -void CheckCaches(bool force_check, std::function log) +void CheckCaches(bool force_check, std::function log, CheckCachesFlags flags) { if (!force_check) { int desync_level = _debug_desync_level; @@ -1398,362 +1399,368 @@ void CheckCaches(bool force_check, std::function log) } \ } - /* Check the town caches. */ - std::vector old_town_caches; - std::vector old_town_stations_nears; - for (const Town *t : Town::Iterate()) { - old_town_caches.push_back(t->cache); - old_town_stations_nears.push_back(t->stations_near); - } + if (flags & CHECK_CACHE_GENERAL) { + /* Check the town caches. */ + std::vector old_town_caches; + std::vector old_town_stations_nears; + for (const Town *t : Town::Iterate()) { + old_town_caches.push_back(t->cache); + old_town_stations_nears.push_back(t->stations_near); + } - std::vector old_station_industries_nears; - std::vector old_station_catchment_tiles; - std::vector old_station_tiles; - for (Station *st : Station::Iterate()) { - old_station_industries_nears.push_back(st->industries_near); - old_station_catchment_tiles.push_back(st->catchment_tiles); - old_station_tiles.push_back(st->station_tiles); - } + std::vector old_station_industries_nears; + std::vector old_station_catchment_tiles; + std::vector old_station_tiles; + for (Station *st : Station::Iterate()) { + old_station_industries_nears.push_back(st->industries_near); + old_station_catchment_tiles.push_back(st->catchment_tiles); + old_station_tiles.push_back(st->station_tiles); + } - std::vector old_industry_stations_nears; - for (Industry *ind : Industry::Iterate()) { - old_industry_stations_nears.push_back(ind->stations_near); - } + std::vector old_industry_stations_nears; + for (Industry *ind : Industry::Iterate()) { + old_industry_stations_nears.push_back(ind->stations_near); + } - extern void RebuildTownCaches(bool cargo_update_required, bool old_map_position); - RebuildTownCaches(false, false); - RebuildSubsidisedSourceAndDestinationCache(); + extern void RebuildTownCaches(bool cargo_update_required, bool old_map_position); + RebuildTownCaches(false, false); + RebuildSubsidisedSourceAndDestinationCache(); - Station::RecomputeCatchmentForAll(); + Station::RecomputeCatchmentForAll(); - uint i = 0; - for (Town *t : Town::Iterate()) { - if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { - CCLOG("town cache mismatch: town %i", (int)t->index); - } - if (old_town_stations_nears[i] != t->stations_near) { - CCLOG("town stations_near mismatch: town %i, (old size: %u, new size: %u)", (int)t->index, (uint)old_town_stations_nears[i].size(), (uint)t->stations_near.size()); - } - i++; - } - i = 0; - for (Station *st : Station::Iterate()) { - if (old_station_industries_nears[i] != st->industries_near) { - CCLOG("station industries_near mismatch: st %i, (old size: %u, new size: %u)", (int)st->index, (uint)old_station_industries_nears[i].size(), (uint)st->industries_near.size()); - } - if (!(old_station_catchment_tiles[i] == st->catchment_tiles)) { - CCLOG("station catchment_tiles mismatch: st %i", (int)st->index); - } - if (!(old_station_tiles[i] == st->station_tiles)) { - CCLOG("station station_tiles mismatch: st %i, (old: %u, new: %u)", (int)st->index, old_station_tiles[i], st->station_tiles); + uint i = 0; + for (Town *t : Town::Iterate()) { + if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { + CCLOG("town cache mismatch: town %i", (int)t->index); + } + if (old_town_stations_nears[i] != t->stations_near) { + CCLOG("town stations_near mismatch: town %i, (old size: %u, new size: %u)", (int)t->index, (uint)old_town_stations_nears[i].size(), (uint)t->stations_near.size()); + } + i++; } - i++; - } - i = 0; - for (Industry *ind : Industry::Iterate()) { - if (old_industry_stations_nears[i] != ind->stations_near) { - CCLOG("industry stations_near mismatch: ind %i, (old size: %u, new size: %u)", (int)ind->index, (uint)old_industry_stations_nears[i].size(), (uint)ind->stations_near.size()); + i = 0; + for (Station *st : Station::Iterate()) { + if (old_station_industries_nears[i] != st->industries_near) { + CCLOG("station industries_near mismatch: st %i, (old size: %u, new size: %u)", (int)st->index, (uint)old_station_industries_nears[i].size(), (uint)st->industries_near.size()); + } + if (!(old_station_catchment_tiles[i] == st->catchment_tiles)) { + CCLOG("station catchment_tiles mismatch: st %i", (int)st->index); + } + if (!(old_station_tiles[i] == st->station_tiles)) { + CCLOG("station station_tiles mismatch: st %i, (old: %u, new: %u)", (int)st->index, old_station_tiles[i], st->station_tiles); + } + i++; } - StationList stlist; - if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) { - stlist.insert(ind->neutral_station); - if (ind->stations_near != stlist) { - CCLOG("industry neutral station stations_near mismatch: ind %i, (recalc size: %u, neutral size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + i = 0; + for (Industry *ind : Industry::Iterate()) { + if (old_industry_stations_nears[i] != ind->stations_near) { + CCLOG("industry stations_near mismatch: ind %i, (old size: %u, new size: %u)", (int)ind->index, (uint)old_industry_stations_nears[i].size(), (uint)ind->stations_near.size()); } - } else { - ForAllStationsAroundTiles(ind->location, [ind, &stlist](Station *st, TileIndex tile) { - if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false; - stlist.insert(st); - return true; - }); - if (ind->stations_near != stlist) { - CCLOG("industry FindStationsAroundTiles mismatch: ind %i, (recalc size: %u, find size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + StationList stlist; + if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) { + stlist.insert(ind->neutral_station); + if (ind->stations_near != stlist) { + CCLOG("industry neutral station stations_near mismatch: ind %i, (recalc size: %u, neutral size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + } + } else { + ForAllStationsAroundTiles(ind->location, [ind, &stlist](Station *st, TileIndex tile) { + if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false; + stlist.insert(st); + return true; + }); + if (ind->stations_near != stlist) { + CCLOG("industry FindStationsAroundTiles mismatch: ind %i, (recalc size: %u, find size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + } } + i++; } - i++; } - /* Check company infrastructure cache. */ - std::vector old_infrastructure; - for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure); - - extern void AfterLoadCompanyStats(); - AfterLoadCompanyStats(); - - i = 0; - for (const Company *c : Company::Iterate()) { - if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { - CCLOG("infrastructure cache mismatch: company %i", (int)c->index); - char buffer[4096]; - old_infrastructure[i].Dump(buffer, lastof(buffer)); - CCLOG("Previous:"); - ProcessLineByLine(buffer, [&](const char *line) { - CCLOG(" %s", line); - }); - c->infrastructure.Dump(buffer, lastof(buffer)); - CCLOG("Recalculated:"); - ProcessLineByLine(buffer, [&](const char *line) { - CCLOG(" %s", line); - }); + if (flags & CHECK_CACHE_INFRA_TOTALS) { + /* Check company infrastructure cache. */ + std::vector old_infrastructure; + for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure); + + extern void AfterLoadCompanyStats(); + AfterLoadCompanyStats(); + + uint i = 0; + for (const Company *c : Company::Iterate()) { + if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { + CCLOG("infrastructure cache mismatch: company %i", (int)c->index); + char buffer[4096]; + old_infrastructure[i].Dump(buffer, lastof(buffer)); + CCLOG("Previous:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); + c->infrastructure.Dump(buffer, lastof(buffer)); + CCLOG("Recalculated:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); + } + i++; } - i++; } - /* Strict checking of the road stop cache entries */ - for (const RoadStop *rs : RoadStop::Iterate()) { - if (IsStandardRoadStopTile(rs->xy)) continue; - - assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); - rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); - rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); - } + if (flags & CHECK_CACHE_GENERAL) { + /* Strict checking of the road stop cache entries */ + for (const RoadStop *rs : RoadStop::Iterate()) { + if (IsStandardRoadStopTile(rs->xy)) continue; - for (Vehicle *v : Vehicle::Iterate()) { - extern bool ValidateVehicleTileHash(const Vehicle *v); - if (!ValidateVehicleTileHash(v)) { - CCLOG("vehicle tile hash mismatch: type %i, vehicle %i, company %i, unit number %i", (int)v->type, v->index, (int)v->owner, v->unitnumber); + assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); + rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); + rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } - extern void FillNewGRFVehicleCache(const Vehicle *v); - if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; + for (Vehicle *v : Vehicle::Iterate()) { + extern bool ValidateVehicleTileHash(const Vehicle *v); + if (!ValidateVehicleTileHash(v)) { + CCLOG("vehicle tile hash mismatch: type %i, vehicle %i, company %i, unit number %i", (int)v->type, v->index, (int)v->owner, v->unitnumber); + } + + extern void FillNewGRFVehicleCache(const Vehicle *v); + if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; - uint length = 0; - for (const Vehicle *u = v; u != nullptr; u = u->Next()) { - if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { - CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (1)"); + uint length = 0; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { + CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (1)"); + } + if (u->type == VEH_TRAIN && u->breakdown_ctr != 0 && !HasBit(Train::From(v)->flags, VRF_CONSIST_BREAKDOWN)) { + CCLOGV("VRF_CONSIST_BREAKDOWN incorrectly not set"); + } + if (u->type == VEH_TRAIN && ((Train::From(u)->track & TRACK_BIT_WORMHOLE && !(Train::From(u)->vehstatus & VS_HIDDEN)) || Train::From(u)->track == TRACK_BIT_DEPOT) && !HasBit(Train::From(v)->flags, VRF_CONSIST_SPEED_REDUCTION)) { + CCLOGV("VRF_CONSIST_SPEED_REDUCTION incorrectly not set"); + } + length++; } - if (u->type == VEH_TRAIN && u->breakdown_ctr != 0 && !HasBit(Train::From(v)->flags, VRF_CONSIST_BREAKDOWN)) { - CCLOGV("VRF_CONSIST_BREAKDOWN incorrectly not set"); + + NewGRFCache *grf_cache = CallocT(length); + VehicleCache *veh_cache = CallocT(length); + GroundVehicleCache *gro_cache = CallocT(length); + AircraftCache *air_cache = CallocT(length); + TrainCache *tra_cache = CallocT(length); + Vehicle **veh_old = CallocT(length); + + length = 0; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + FillNewGRFVehicleCache(u); + grf_cache[length] = u->grf_cache; + veh_cache[length] = u->vcache; + switch (u->type) { + case VEH_TRAIN: + gro_cache[length] = Train::From(u)->gcache; + tra_cache[length] = Train::From(u)->tcache; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) Train::From(u), sizeof(Train)); + break; + case VEH_ROAD: + gro_cache[length] = RoadVehicle::From(u)->gcache; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) RoadVehicle::From(u), sizeof(RoadVehicle)); + break; + case VEH_AIRCRAFT: + air_cache[length] = Aircraft::From(u)->acache; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) Aircraft::From(u), sizeof(Aircraft)); + break; + default: + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) u, sizeof(Vehicle)); + break; + } + length++; } - if (u->type == VEH_TRAIN && ((Train::From(u)->track & TRACK_BIT_WORMHOLE && !(Train::From(u)->vehstatus & VS_HIDDEN)) || Train::From(u)->track == TRACK_BIT_DEPOT) && !HasBit(Train::From(v)->flags, VRF_CONSIST_SPEED_REDUCTION)) { - CCLOGV("VRF_CONSIST_SPEED_REDUCTION incorrectly not set"); + + switch (v->type) { + case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; + case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; + case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; + case VEH_SHIP: Ship::From(v)->UpdateCache(); break; + default: break; } - length++; - } - NewGRFCache *grf_cache = CallocT(length); - VehicleCache *veh_cache = CallocT(length); - GroundVehicleCache *gro_cache = CallocT(length); - AircraftCache *air_cache = CallocT(length); - TrainCache *tra_cache = CallocT(length); - Vehicle **veh_old = CallocT(length); - - length = 0; - for (const Vehicle *u = v; u != nullptr; u = u->Next()) { - FillNewGRFVehicleCache(u); - grf_cache[length] = u->grf_cache; - veh_cache[length] = u->vcache; - switch (u->type) { - case VEH_TRAIN: - gro_cache[length] = Train::From(u)->gcache; - tra_cache[length] = Train::From(u)->tcache; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) Train::From(u), sizeof(Train)); - break; - case VEH_ROAD: - gro_cache[length] = RoadVehicle::From(u)->gcache; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) RoadVehicle::From(u), sizeof(RoadVehicle)); - break; - case VEH_AIRCRAFT: - air_cache[length] = Aircraft::From(u)->acache; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) Aircraft::From(u), sizeof(Aircraft)); - break; - default: - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) u, sizeof(Vehicle)); - break; + length = 0; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + FillNewGRFVehicleCache(u); + if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { + CCLOGV("newgrf cache mismatch"); + } + if (veh_cache[length].cached_max_speed != u->vcache.cached_max_speed || veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period || + veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect || HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)) { + CCLOGV("vehicle cache mismatch: %c%c%c%c", + veh_cache[length].cached_max_speed != u->vcache.cached_max_speed ? 'm' : '-', + veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ? 'c' : '-', + veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect ? 'v' : '-', + HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT) ? 'l' : '-'); + } + if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { + CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (2)"); + } + if (veh_old[length]->acceleration != u->acceleration) { + CCLOGV("acceleration mismatch"); + } + if (veh_old[length]->breakdown_chance != u->breakdown_chance) { + CCLOGV("breakdown_chance mismatch"); + } + if (veh_old[length]->breakdown_ctr != u->breakdown_ctr) { + CCLOGV("breakdown_ctr mismatch"); + } + if (veh_old[length]->breakdown_delay != u->breakdown_delay) { + CCLOGV("breakdown_delay mismatch"); + } + if (veh_old[length]->breakdowns_since_last_service != u->breakdowns_since_last_service) { + CCLOGV("breakdowns_since_last_service mismatch"); + } + if (veh_old[length]->breakdown_severity != u->breakdown_severity) { + CCLOGV("breakdown_severity mismatch"); + } + if (veh_old[length]->breakdown_type != u->breakdown_type) { + CCLOGV("breakdown_type mismatch"); + } + if (veh_old[length]->vehicle_flags != u->vehicle_flags) { + CCLOGV("vehicle_flags mismatch"); + } + auto print_gv_cache_diff = [&](const char *vtype, const GroundVehicleCache &a, const GroundVehicleCache &b) { + CCLOGV("%s ground vehicle cache mismatch: %c%c%c%c%c%c%c%c%c%c", + vtype, + a.cached_weight != b.cached_weight ? 'w' : '-', + a.cached_slope_resistance != b.cached_slope_resistance ? 'r' : '-', + a.cached_max_te != b.cached_max_te ? 't' : '-', + a.cached_axle_resistance != b.cached_axle_resistance ? 'a' : '-', + a.cached_max_track_speed != b.cached_max_track_speed ? 's' : '-', + a.cached_power != b.cached_power ? 'p' : '-', + a.cached_air_drag != b.cached_air_drag ? 'd' : '-', + a.cached_total_length != b.cached_total_length ? 'l' : '-', + a.first_engine != b.first_engine ? 'e' : '-', + a.cached_veh_length != b.cached_veh_length ? 'L' : '-'); + }; + switch (u->type) { + case VEH_TRAIN: + if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { + print_gv_cache_diff("train", gro_cache[length], Train::From(u)->gcache); + } + if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { + CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c%c", + tra_cache[length].cached_override != Train::From(u)->tcache.cached_override ? 'o' : '-', + tra_cache[length].cached_tflags != Train::From(u)->tcache.cached_tflags ? 'f' : '-', + tra_cache[length].cached_num_engines != Train::From(u)->tcache.cached_num_engines ? 'e' : '-', + tra_cache[length].cached_centre_mass != Train::From(u)->tcache.cached_centre_mass ? 'm' : '-', + tra_cache[length].cached_veh_weight != Train::From(u)->tcache.cached_veh_weight ? 'w' : '-', + tra_cache[length].cached_uncapped_decel != Train::From(u)->tcache.cached_uncapped_decel ? 'D' : '-', + tra_cache[length].cached_deceleration != Train::From(u)->tcache.cached_deceleration ? 'd' : '-', + tra_cache[length].user_def_data != Train::From(u)->tcache.user_def_data ? 'u' : '-', + tra_cache[length].cached_max_curve_speed != Train::From(u)->tcache.cached_max_curve_speed ? 'c' : '-'); + } + if (Train::From(veh_old[length])->railtype != Train::From(u)->railtype) { + CCLOGV("railtype mismatch"); + } + if (Train::From(veh_old[length])->compatible_railtypes != Train::From(u)->compatible_railtypes) { + CCLOGV("compatible_railtypes mismatch"); + } + if (Train::From(veh_old[length])->flags != Train::From(u)->flags) { + CCLOGV("train flags mismatch"); + } + break; + case VEH_ROAD: + if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { + print_gv_cache_diff("road vehicle", gro_cache[length], Train::From(u)->gcache); + } + break; + case VEH_AIRCRAFT: + if (memcmp(&air_cache[length], &Aircraft::From(u)->acache, sizeof(AircraftCache)) != 0) { + CCLOGV("Aircraft vehicle cache mismatch: %c%c", + air_cache[length].cached_max_range != Aircraft::From(u)->acache.cached_max_range ? 'r' : '-', + air_cache[length].cached_max_range_sqr != Aircraft::From(u)->acache.cached_max_range_sqr ? 's' : '-'); + } + break; + default: + break; + } + free(veh_old[length]); + length++; } - length++; + + free(grf_cache); + free(veh_cache); + free(gro_cache); + free(air_cache); + free(tra_cache); + free(veh_old); } - switch (v->type) { - case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; - case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; - case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; - case VEH_SHIP: Ship::From(v)->UpdateCache(); break; - default: break; + /* Check whether the caches are still valid */ + for (Vehicle *v : Vehicle::Iterate()) { + byte buff[sizeof(VehicleCargoList)]; + memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); + v->cargo.InvalidateCache(); + assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } - length = 0; - for (const Vehicle *u = v; u != nullptr; u = u->Next()) { - FillNewGRFVehicleCache(u); - if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { - CCLOGV("newgrf cache mismatch"); - } - if (veh_cache[length].cached_max_speed != u->vcache.cached_max_speed || veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period || - veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect || HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)) { - CCLOGV("vehicle cache mismatch: %c%c%c%c", - veh_cache[length].cached_max_speed != u->vcache.cached_max_speed ? 'm' : '-', - veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ? 'c' : '-', - veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect ? 'v' : '-', - HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT) ? 'l' : '-'); - } - if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { - CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (2)"); - } - if (veh_old[length]->acceleration != u->acceleration) { - CCLOGV("acceleration mismatch"); - } - if (veh_old[length]->breakdown_chance != u->breakdown_chance) { - CCLOGV("breakdown_chance mismatch"); - } - if (veh_old[length]->breakdown_ctr != u->breakdown_ctr) { - CCLOGV("breakdown_ctr mismatch"); - } - if (veh_old[length]->breakdown_delay != u->breakdown_delay) { - CCLOGV("breakdown_delay mismatch"); + for (Station *st : Station::Iterate()) { + for (CargoID c = 0; c < NUM_CARGO; c++) { + byte buff[sizeof(StationCargoList)]; + memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); + st->goods[c].cargo.InvalidateCache(); + assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } - if (veh_old[length]->breakdowns_since_last_service != u->breakdowns_since_last_service) { - CCLOGV("breakdowns_since_last_service mismatch"); - } - if (veh_old[length]->breakdown_severity != u->breakdown_severity) { - CCLOGV("breakdown_severity mismatch"); - } - if (veh_old[length]->breakdown_type != u->breakdown_type) { - CCLOGV("breakdown_type mismatch"); + + /* Check docking tiles */ + TileArea ta; + std::map docking_tiles; + TILE_AREA_LOOP(tile, st->docking_station) { + ta.Add(tile); + docking_tiles[tile] = IsDockingTile(tile); } - if (veh_old[length]->vehicle_flags != u->vehicle_flags) { - CCLOGV("vehicle_flags mismatch"); + UpdateStationDockingTiles(st); + if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) { + CCLOG("station docking mismatch: station %i, company %i, prev: (%X, %u, %u), recalc: (%X, %u, %u)", + st->index, (int)st->owner, ta.tile, ta.w, ta.h, st->docking_station.tile, st->docking_station.w, st->docking_station.h); } - auto print_gv_cache_diff = [&](const char *vtype, const GroundVehicleCache &a, const GroundVehicleCache &b) { - CCLOGV("%s ground vehicle cache mismatch: %c%c%c%c%c%c%c%c%c%c", - vtype, - a.cached_weight != b.cached_weight ? 'w' : '-', - a.cached_slope_resistance != b.cached_slope_resistance ? 'r' : '-', - a.cached_max_te != b.cached_max_te ? 't' : '-', - a.cached_axle_resistance != b.cached_axle_resistance ? 'a' : '-', - a.cached_max_track_speed != b.cached_max_track_speed ? 's' : '-', - a.cached_power != b.cached_power ? 'p' : '-', - a.cached_air_drag != b.cached_air_drag ? 'd' : '-', - a.cached_total_length != b.cached_total_length ? 'l' : '-', - a.first_engine != b.first_engine ? 'e' : '-', - a.cached_veh_length != b.cached_veh_length ? 'L' : '-'); - }; - switch (u->type) { - case VEH_TRAIN: - if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - print_gv_cache_diff("train", gro_cache[length], Train::From(u)->gcache); - } - if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { - CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c%c", - tra_cache[length].cached_override != Train::From(u)->tcache.cached_override ? 'o' : '-', - tra_cache[length].cached_tflags != Train::From(u)->tcache.cached_tflags ? 'f' : '-', - tra_cache[length].cached_num_engines != Train::From(u)->tcache.cached_num_engines ? 'e' : '-', - tra_cache[length].cached_centre_mass != Train::From(u)->tcache.cached_centre_mass ? 'm' : '-', - tra_cache[length].cached_veh_weight != Train::From(u)->tcache.cached_veh_weight ? 'w' : '-', - tra_cache[length].cached_uncapped_decel != Train::From(u)->tcache.cached_uncapped_decel ? 'D' : '-', - tra_cache[length].cached_deceleration != Train::From(u)->tcache.cached_deceleration ? 'd' : '-', - tra_cache[length].user_def_data != Train::From(u)->tcache.user_def_data ? 'u' : '-', - tra_cache[length].cached_max_curve_speed != Train::From(u)->tcache.cached_max_curve_speed ? 'c' : '-'); - } - if (Train::From(veh_old[length])->railtype != Train::From(u)->railtype) { - CCLOGV("railtype mismatch"); - } - if (Train::From(veh_old[length])->compatible_railtypes != Train::From(u)->compatible_railtypes) { - CCLOGV("compatible_railtypes mismatch"); - } - if (Train::From(veh_old[length])->flags != Train::From(u)->flags) { - CCLOGV("train flags mismatch"); - } - break; - case VEH_ROAD: - if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - print_gv_cache_diff("road vehicle", gro_cache[length], Train::From(u)->gcache); - } - break; - case VEH_AIRCRAFT: - if (memcmp(&air_cache[length], &Aircraft::From(u)->acache, sizeof(AircraftCache)) != 0) { - CCLOGV("Aircraft vehicle cache mismatch: %c%c", - air_cache[length].cached_max_range != Aircraft::From(u)->acache.cached_max_range ? 'r' : '-', - air_cache[length].cached_max_range_sqr != Aircraft::From(u)->acache.cached_max_range_sqr ? 's' : '-'); - } - break; - default: - break; + TILE_AREA_LOOP(tile, ta) { + if (docking_tiles[tile] != IsDockingTile(tile)) { + CCLOG("docking tile mismatch: tile %i", (int)tile); + } } - free(veh_old[length]); - length++; } - free(grf_cache); - free(veh_cache); - free(gro_cache); - free(air_cache); - free(tra_cache); - free(veh_old); - } - - /* Check whether the caches are still valid */ - for (Vehicle *v : Vehicle::Iterate()) { - byte buff[sizeof(VehicleCargoList)]; - memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); - v->cargo.InvalidateCache(); - assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); - } - - for (Station *st : Station::Iterate()) { - for (CargoID c = 0; c < NUM_CARGO; c++) { - byte buff[sizeof(StationCargoList)]; - memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); - st->goods[c].cargo.InvalidateCache(); - assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); + for (OrderList *order_list : OrderList::Iterate()) { + order_list->DebugCheckSanity(); } - /* Check docking tiles */ - TileArea ta; - std::map docking_tiles; - TILE_AREA_LOOP(tile, st->docking_station) { - ta.Add(tile); - docking_tiles[tile] = IsDockingTile(tile); - } - UpdateStationDockingTiles(st); - if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) { - CCLOG("station docking mismatch: station %i, company %i, prev: (%X, %u, %u), recalc: (%X, %u, %u)", - st->index, (int)st->owner, ta.tile, ta.w, ta.h, st->docking_station.tile, st->docking_station.w, st->docking_station.h); + extern void ValidateVehicleTickCaches(); + ValidateVehicleTickCaches(); + + for (Vehicle *v : Vehicle::Iterate()) { + if (v->Previous()) assert_msg(v->Previous()->Next() == v, "%u", v->index); + if (v->Next()) assert_msg(v->Next()->Previous() == v, "%u", v->index); } - TILE_AREA_LOOP(tile, ta) { - if (docking_tiles[tile] != IsDockingTile(tile)) { - CCLOG("docking tile mismatch: tile %i", (int)tile); - } + for (const TemplateVehicle *tv : TemplateVehicle::Iterate()) { + if (tv->Prev()) assert_msg(tv->Prev()->Next() == tv, "%u", tv->index); + if (tv->Next()) assert_msg(tv->Next()->Prev() == tv, "%u", tv->index); } - } - for (OrderList *order_list : OrderList::Iterate()) { - order_list->DebugCheckSanity(); - } + if (!TraceRestrictSlot::ValidateVehicleIndex()) CCLOG("Trace restrict slot vehicle index validation failed"); + TraceRestrictSlot::ValidateSlotOccupants(log); - extern void ValidateVehicleTickCaches(); - ValidateVehicleTickCaches(); + if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed"); - for (Vehicle *v : Vehicle::Iterate()) { - if (v->Previous()) assert_msg(v->Previous()->Next() == v, "%u", v->index); - if (v->Next()) assert_msg(v->Next()->Previous() == v, "%u", v->index); - } - for (const TemplateVehicle *tv : TemplateVehicle::Iterate()) { - if (tv->Prev()) assert_msg(tv->Prev()->Next() == tv, "%u", tv->index); - if (tv->Next()) assert_msg(tv->Next()->Prev() == tv, "%u", tv->index); - } - - if (!TraceRestrictSlot::ValidateVehicleIndex()) CCLOG("Trace restrict slot vehicle index validation failed"); - TraceRestrictSlot::ValidateSlotOccupants(log); - - if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed"); - - if (_order_destination_refcount_map_valid) { - btree::btree_map saved_order_destination_refcount_map = std::move(_order_destination_refcount_map); - for (auto iter = saved_order_destination_refcount_map.begin(); iter != saved_order_destination_refcount_map.end();) { - if (iter->second == 0) { - iter = saved_order_destination_refcount_map.erase(iter); - } else { - ++iter; + if (_order_destination_refcount_map_valid) { + btree::btree_map saved_order_destination_refcount_map = std::move(_order_destination_refcount_map); + for (auto iter = saved_order_destination_refcount_map.begin(); iter != saved_order_destination_refcount_map.end();) { + if (iter->second == 0) { + iter = saved_order_destination_refcount_map.erase(iter); + } else { + ++iter; + } } + IntialiseOrderDestinationRefcountMap(); + if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch"); + } else { + CCLOG("Order destination refcount map not valid"); } - IntialiseOrderDestinationRefcountMap(); - if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch"); - } else { - CCLOG("Order destination refcount map not valid"); } #undef CCLOGV From 1b8bbdaf76d99a3dfa7f94317322989c7c15a649 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 22:26:25 +0100 Subject: [PATCH 20/43] Add chicken bit for CheckCaches call after DoCommandP --- src/command.cpp | 10 ++++++++++ src/debug_settings.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/command.cpp b/src/command.cpp index e05765602c..f4a8e3555a 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -30,6 +30,8 @@ #include "core/random_func.hpp" #include "settings_func.h" #include "signal_func.h" +#include "debug_settings.h" +#include "debug_desync.h" #include #include "table/strings.h" @@ -889,6 +891,10 @@ bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, C if (!random_state.Check()) log_flags |= CLEF_RANDOM; AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags); + if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_POST_COMMAND)) && !(GetCommandFlags(cmd) & CMD_LOG_AUX)) { + CheckCaches(true, nullptr, CHECK_CACHE_INFRA_TOTALS); + } + if (res.Failed()) { /* Only show the error when it's for us. */ StringID error_part1 = GB(cmd, 16, 16); @@ -929,6 +935,10 @@ CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, ui if (!random_state.Check()) log_flags |= CLEF_RANDOM; AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags); + if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_POST_COMMAND)) && !(GetCommandFlags(cmd) & CMD_LOG_AUX)) { + CheckCaches(true, nullptr, CHECK_CACHE_INFRA_TOTALS); + } + return res; } diff --git a/src/debug_settings.h b/src/debug_settings.h index cc031e2756..63b9350a09 100644 --- a/src/debug_settings.h +++ b/src/debug_settings.h @@ -17,6 +17,7 @@ enum ChickenBitFlags { DCBF_VEH_TICK_CACHE = 0, DCBF_MP_NO_STATE_CSUM_CHECK = 1, DCBF_DESYNC_CHECK_PERIODIC = 2, + DCBF_DESYNC_CHECK_POST_COMMAND = 3, }; inline bool HasChickenBit(ChickenBitFlags flag) From 24fdc8331b464f4d93c79d05051f55e112b4c92d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 23:57:27 +0100 Subject: [PATCH 21/43] Add CheckCaches mode to emit a log/save/screenshot on detected issue --- src/company_cmd.cpp | 2 +- src/console_cmds.cpp | 2 +- src/crashlog.cpp | 111 ++++++++++++++++++++++++++++++++ src/crashlog.h | 7 ++ src/debug_desync.h | 3 +- src/economy.cpp | 2 +- src/openttd.cpp | 20 +++++- src/os/macosx/crashlog_osx.cpp | 7 ++ src/os/unix/crashlog_unix.cpp | 6 ++ src/os/windows/crashlog_win.cpp | 6 ++ 10 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 965816ec3e..900ccb739b 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -938,7 +938,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0); - CheckCaches(true, nullptr); + CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG); break; } diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 4cec71eae2..6d831ca5af 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2688,7 +2688,7 @@ DEF_CONSOLE_CMD(ConCheckCaches) if (broadcast) { DoCommandP(0, 0, 0, CMD_DESYNC_CHECK); } else { - CheckCaches(true, nullptr); + CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG); } return true; diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 0fbd23ea91..db68d5dd7e 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -535,6 +535,62 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last, const DesyncE return buffer; } +/** + * Fill the crash log buffer with all data of an inconsistency event. + * @param buffer The begin where to write at. + * @param last The last position in the buffer to write to. + * @return the position of the \c '\0' character after the buffer. + */ +char *CrashLog::FillInconsistencyLog(char *buffer, const char *last, const InconsistencyExtraInfo &info) const +{ + time_t cur_time = time(nullptr); + buffer += seprintf(buffer, last, "*** OpenTTD Inconsistency Report ***\n\n"); + + buffer += seprintf(buffer, last, "Inconsistency at: %s", asctime(gmtime(&cur_time))); + +#ifdef USE_SCOPE_INFO + buffer += WriteScopeLog(buffer, last); +#endif + + buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i) (DL: %u)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter, _settings_game.economy.day_length_factor); + if (_game_load_time != 0) { + buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s", + _game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time))); + } + if (_networking && !_network_server) { + extern Date _last_sync_date; + extern DateFract _last_sync_date_fract; + extern uint8 _last_sync_tick_skip_counter; + + YearMonthDay ymd; + ConvertDateToYMD(_last_sync_date, &ymd); + buffer += seprintf(buffer, last, "Last sync at: %i-%02i-%02i (%i, %i)", + ymd.year, ymd.month + 1, ymd.day, _last_sync_date_fract, _last_sync_tick_skip_counter); + } + buffer += seprintf(buffer, last, "\n"); + + buffer = this->LogOpenTTDVersion(buffer, last); + buffer = this->LogOSVersion(buffer, last); + buffer = this->LogCompiler(buffer, last); + buffer = this->LogOSVersionDetail(buffer, last); + buffer = this->LogConfiguration(buffer, last); + buffer = this->LogLibraries(buffer, last); + buffer = this->LogGamelog(buffer, last); + buffer = this->LogRecentNews(buffer, last); + buffer = this->LogCommandLog(buffer, last); + buffer = DumpDesyncMsgLog(buffer, last); + + if (!info.check_caches_result.empty()) { + buffer += seprintf(buffer, last, "CheckCaches:\n"); + for (const std::string &str : info.check_caches_result) { + buffer += seprintf(buffer, last, " %s\n", str.c_str()); + } + } + + buffer += seprintf(buffer, last, "*** End of OpenTTD Inconsistency Report ***\n"); + return buffer; +} + /** * Fill the version info log buffer. * @param buffer The begin where to write at. @@ -758,6 +814,61 @@ bool CrashLog::MakeDesyncCrashLog(const std::string *log_in, std::string *log_ou return ret; } +/** + * Makes an inconsistency log, writes it to a file and then subsequently tries + * to make a crash savegame. It uses DEBUG to write + * information like paths to the console. + * @return true when everything is made successfully. + */ +bool CrashLog::MakeInconsistencyLog(const InconsistencyExtraInfo &info) const +{ + char filename[MAX_PATH]; + char buffer[65536 * 2]; + bool ret = true; + + char name_buffer[64]; + char *name_buffer_date = name_buffer + seprintf(name_buffer, lastof(name_buffer), "inconsistency-"); + time_t cur_time = time(nullptr); + strftime(name_buffer_date, lastof(name_buffer) - name_buffer_date, "%Y%m%dT%H%M%SZ", gmtime(&cur_time)); + + printf("Inconsistency encountered, generating diagnostics log...\n"); + this->FillInconsistencyLog(buffer, lastof(buffer), info); + + bool bret = this->WriteCrashLog(buffer, filename, lastof(filename), name_buffer); + if (bret) { + printf("Inconsistency log written to %s. Please add this file to any bug reports.\n\n", filename); + } else { + printf("Writing inconsistency log failed.\n\n"); + ret = false; + } + + _savegame_DBGL_data = buffer; + _save_DBGC_data = true; + bret = this->WriteSavegame(filename, lastof(filename), name_buffer); + if (bret) { + printf("info savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename); + } else { + ret = false; + printf("Writing inconsistency savegame failed. Please attach the last (auto)save to any bug reports.\n\n"); + } + _savegame_DBGL_data = nullptr; + _save_DBGC_data = false; + + if (!(_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == nullptr)) { + SetScreenshotAuxiliaryText("Inconsistency Log", buffer); + bret = this->WriteScreenshot(filename, lastof(filename), name_buffer); + if (bret) { + printf("Inconsistency screenshot written to %s. Please add this file to any bug reports.\n\n", filename); + } else { + ret = false; + printf("Writing inconsistency screenshot failed.\n\n"); + } + ClearScreenshotAuxiliaryText(); + } + + return ret; +} + /** * Makes a version info log, writes it to a file. It uses DEBUG to write * information like paths to the console. diff --git a/src/crashlog.h b/src/crashlog.h index ee1ed05564..a7c4a99d8d 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -27,6 +27,10 @@ struct DesyncExtraInfo { }; DECLARE_ENUM_AS_BIT_SET(DesyncExtraInfo::Flags) +struct InconsistencyExtraInfo { + std::vector check_caches_result; +}; + /** * Helper class for creating crash logs. */ @@ -130,6 +134,7 @@ public: char *FillCrashLog(char *buffer, const char *last) const; char *FillDesyncCrashLog(char *buffer, const char *last, const DesyncExtraInfo &info) const; + char *FillInconsistencyLog(char *buffer, const char *last, const InconsistencyExtraInfo &info) const; char *FillVersionInfoLog(char *buffer, const char *last) const; bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name = "crash", FILE **crashlog_file = nullptr) const; @@ -148,6 +153,7 @@ public: bool MakeCrashLog(); bool MakeDesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info) const; + bool MakeInconsistencyLog(const InconsistencyExtraInfo &info) const; bool MakeVersionInfoLog() const; bool MakeCrashSavegameAndScreenshot() const; @@ -165,6 +171,7 @@ public: static void InitThread(); static void DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info); + static void InconsistencyLog(const InconsistencyExtraInfo &info); static void VersionInfoLog(); static void SetErrorMessage(const char *message); diff --git a/src/debug_desync.h b/src/debug_desync.h index 98b8760f00..121b831dc0 100644 --- a/src/debug_desync.h +++ b/src/debug_desync.h @@ -16,7 +16,8 @@ enum CheckCachesFlags : uint32 { CHECK_CACHE_NONE = 0, CHECK_CACHE_GENERAL = 1 << 0, CHECK_CACHE_INFRA_TOTALS = 1 << 1, - CHECK_CACHE_ALL = UINT32_MAX, + CHECK_CACHE_ALL = UINT16_MAX, + CHECK_CACHE_EMIT_LOG = 1 << 16, }; DECLARE_ENUM_AS_BIT_SET(CheckCachesFlags) diff --git a/src/economy.cpp b/src/economy.cpp index 6098f835ae..522927041d 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -2288,7 +2288,7 @@ static void DoAcquireCompany(Company *c) delete c; - CheckCaches(true, nullptr); + CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG); } extern int GetAmountOwnedBy(const Company *c, Owner owner); diff --git a/src/openttd.cpp b/src/openttd.cpp index 0cb3d7221f..c8739b5fde 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1373,6 +1373,13 @@ void CheckCaches(bool force_check, std::function log, CheckC if (desync_level == 1 && _scaled_date_ticks % 500 != 0) return; } + std::vector saved_messages; + if (flags & CHECK_CACHE_EMIT_LOG) { + log = [&saved_messages](const char *str) { + saved_messages.emplace_back(str); + }; + } + char cclog_buffer[1024]; #define CCLOG(...) { \ seprintf(cclog_buffer, lastof(cclog_buffer), __VA_ARGS__); \ @@ -1763,6 +1770,15 @@ void CheckCaches(bool force_check, std::function log, CheckC } } + if ((flags & CHECK_CACHE_EMIT_LOG) && !saved_messages.empty()) { + InconsistencyExtraInfo info; + info.check_caches_result = std::move(saved_messages); + CrashLog::InconsistencyLog(info); + for (std::string &str : info.check_caches_result) { + LogDesyncMsg(std::move(str)); + } + } + #undef CCLOGV #undef CCLOG } @@ -1779,7 +1795,7 @@ void CheckCaches(bool force_check, std::function log, CheckC CommandCost CmdDesyncCheck(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (flags & DC_EXEC) { - CheckCaches(true, nullptr); + CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG); } return CommandCost(); @@ -1836,7 +1852,7 @@ void StateGameLoop() SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false); } - CheckCaches(false, nullptr); + CheckCaches(false, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG); /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */ diff --git a/src/os/macosx/crashlog_osx.cpp b/src/os/macosx/crashlog_osx.cpp index 1811aa5c41..5d7c9993b1 100644 --- a/src/os/macosx/crashlog_osx.cpp +++ b/src/os/macosx/crashlog_osx.cpp @@ -492,6 +492,13 @@ void CDECL HandleCrash(int signum, siginfo_t *si, void *context) log.MakeDesyncCrashLog(log_in, log_out, info); } +/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info) +{ + CrashLogOSX log(CrashLogOSX::DesyncTag{}); + log.MakeInconsistencyLog(info); +} + + /* static */ void CrashLog::VersionInfoLog() { CrashLogOSX log(CrashLogOSX::DesyncTag{}); diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index 94ce535a9d..bfaee844d0 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -628,6 +628,12 @@ static void CDECL HandleCrash(int signum) log.MakeDesyncCrashLog(log_in, log_out, info); } +/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info) +{ + CrashLogUnix log(CrashLogUnix::DesyncTag{}); + log.MakeInconsistencyLog(info); +} + /* static */ void CrashLog::VersionInfoLog() { CrashLogUnix log(CrashLogUnix::DesyncTag{}); diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 50e6c9596d..2f728573b2 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -758,6 +758,12 @@ static void CDECL CustomAbort(int signal) log.MakeDesyncCrashLog(log_in, log_out, info); } +/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info) +{ + CrashLogWindows log(nullptr); + log.MakeInconsistencyLog(info); +} + /* static */ void CrashLog::VersionInfoLog() { CrashLogWindows log(nullptr); From 6b250c203c116a00e0cc2ae895a105b21ea68748 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 23:58:35 +0100 Subject: [PATCH 22/43] Add chicken bit to control CheckCaches periodic/post-command flags --- src/command.cpp | 8 ++++++-- src/debug_settings.h | 1 + src/openttd.cpp | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index f4a8e3555a..b63b416141 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -892,7 +892,9 @@ bool DoCommandPEx(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd, C AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags); if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_POST_COMMAND)) && !(GetCommandFlags(cmd) & CMD_LOG_AUX)) { - CheckCaches(true, nullptr, CHECK_CACHE_INFRA_TOTALS); + CheckCachesFlags flags = CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG; + if (HasChickenBit(DCBF_DESYNC_CHECK_NO_GENERAL)) flags &= ~CHECK_CACHE_GENERAL; + CheckCaches(true, nullptr, flags); } if (res.Failed()) { @@ -936,7 +938,9 @@ CommandCost DoCommandPScript(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, ui AppendCommandLogEntry(res, tile, p1, p2, p3, cmd, log_flags); if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_POST_COMMAND)) && !(GetCommandFlags(cmd) & CMD_LOG_AUX)) { - CheckCaches(true, nullptr, CHECK_CACHE_INFRA_TOTALS); + CheckCachesFlags flags = CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG; + if (HasChickenBit(DCBF_DESYNC_CHECK_NO_GENERAL)) flags &= ~CHECK_CACHE_GENERAL; + CheckCaches(true, nullptr, flags); } return res; diff --git a/src/debug_settings.h b/src/debug_settings.h index 63b9350a09..9d770a6f11 100644 --- a/src/debug_settings.h +++ b/src/debug_settings.h @@ -18,6 +18,7 @@ enum ChickenBitFlags { DCBF_MP_NO_STATE_CSUM_CHECK = 1, DCBF_DESYNC_CHECK_PERIODIC = 2, DCBF_DESYNC_CHECK_POST_COMMAND = 3, + DCBF_DESYNC_CHECK_NO_GENERAL = 4, }; inline bool HasChickenBit(ChickenBitFlags flag) diff --git a/src/openttd.cpp b/src/openttd.cpp index c8739b5fde..a61fe0bc8b 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1364,7 +1364,10 @@ void CheckCaches(bool force_check, std::function log, CheckC if (!force_check) { int desync_level = _debug_desync_level; - if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_PERIODIC)) && desync_level < 1) desync_level = 1; + if (unlikely(HasChickenBit(DCBF_DESYNC_CHECK_PERIODIC)) && desync_level < 1) { + desync_level = 1; + if (HasChickenBit(DCBF_DESYNC_CHECK_NO_GENERAL)) flags &= ~CHECK_CACHE_GENERAL; + } /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ From 1451aa76ffeefa96eba33f259fbfa2ad952c365e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 01:02:39 +0100 Subject: [PATCH 23/43] Add console command to dump vehicle info --- src/console_cmds.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 6d831ca5af..cbaa442928 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -54,6 +54,7 @@ #include "base_media_base.h" #include "debug_settings.h" #include "debug_desync.h" +#include "scope_info.h" #include #include "safeguards.h" @@ -2623,6 +2624,23 @@ DEF_CONSOLE_CMD(ConDumpCargoTypes) return true; } +DEF_CONSOLE_CMD(ConDumpVehicle) +{ + if (argc != 2) { + IConsoleHelp("Debug: Show vehicle information. Usage: 'dump_vehicle '"); + return true; + } + + const Vehicle *v = Vehicle::GetIfValid(atoi(argv[1])); + if (v != nullptr) { + IConsolePrint(CC_DEFAULT, scope_dumper().VehicleInfo(v)); + } else { + IConsolePrint(CC_DEFAULT, "No such vehicle"); + } + + return true; +} + /** * Dump the state of a tile on the map. * param x tile number or tile x coordinate. @@ -3465,6 +3483,7 @@ void IConsoleStdLibRegister() IConsole::CmdRegister("dump_rail_types", ConDumpRailTypes, nullptr, true); IConsole::CmdRegister("dump_bridge_types", ConDumpBridgeTypes, nullptr, true); IConsole::CmdRegister("dump_cargo_types", ConDumpCargoTypes, nullptr, true); + IConsole::CmdRegister("dump_vehicle", ConDumpVehicle, nullptr, true); IConsole::CmdRegister("dump_tile", ConDumpTile, nullptr, true); IConsole::CmdRegister("check_caches", ConCheckCaches, nullptr, true); IConsole::CmdRegister("show_town_window", ConShowTownWindow, nullptr, true); From 2e022d519464c8b100b10b692522e5ab98c754e1 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 20:29:02 +0100 Subject: [PATCH 24/43] Move game events to new event_logs header/cpp files --- src/CMakeLists.txt | 2 ++ src/console_cmds.cpp | 1 + src/crashlog.cpp | 1 + src/disaster_vehicle.cpp | 1 + src/economy.cpp | 1 + src/event_logs.cpp | 37 +++++++++++++++++++++++++++++++++ src/event_logs.h | 42 ++++++++++++++++++++++++++++++++++++++ src/industry_cmd.cpp | 1 + src/misc.cpp | 1 + src/openttd.cpp | 24 +--------------------- src/openttd.h | 26 ----------------------- src/saveload/afterload.cpp | 1 + src/saveload/misc_sl.cpp | 1 + src/train_cmd.cpp | 1 + 14 files changed, 91 insertions(+), 49 deletions(-) create mode 100644 src/event_logs.cpp create mode 100644 src/event_logs.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3ef71917a..450e7078f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -157,6 +157,8 @@ add_files( engine_type.h error.h error_gui.cpp + event_logs.cpp + event_logs.h fileio.cpp fileio_func.h fileio_type.h diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index cbaa442928..52b2bc4afc 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -55,6 +55,7 @@ #include "debug_settings.h" #include "debug_desync.h" #include "scope_info.h" +#include "event_logs.h" #include #include "safeguards.h" diff --git a/src/crashlog.cpp b/src/crashlog.cpp index db68d5dd7e..63212d29a4 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -31,6 +31,7 @@ #include "command_func.h" #include "thread.h" #include "debug_desync.h" +#include "event_logs.h" #include "ai/ai_info.hpp" #include "game/game.hpp" diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 3c234e499e..e218fc7bf3 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -46,6 +46,7 @@ #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "core/checksum_func.hpp" +#include "event_logs.h" #include "table/strings.h" diff --git a/src/economy.cpp b/src/economy.cpp index 522927041d..501db7006d 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -55,6 +55,7 @@ #include "scope_info.h" #include "pathfinder/yapf/yapf_cache.h" #include "debug_desync.h" +#include "event_logs.h" #include "table/strings.h" #include "table/pricebase.h" diff --git a/src/event_logs.cpp b/src/event_logs.cpp new file mode 100644 index 0000000000..10bab41261 --- /dev/null +++ b/src/event_logs.cpp @@ -0,0 +1,37 @@ +/* + * 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 event_logs.cpp Functions related to event logging. */ + +#include "stdafx.h" +#include "event_logs.h" +#include "string_func.h" + +#include "safeguards.h" + +GameEventFlags _game_events_since_load; +GameEventFlags _game_events_overall; + +time_t _game_load_time; + +char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last) +{ + if (b <= last) *b = 0; + auto dump = [&](char c, GameEventFlags ev) { + if (events & ev) b += seprintf(b, last, "%c", c); + }; + dump('d', GEF_COMPANY_DELETE); + dump('m', GEF_COMPANY_MERGE); + dump('n', GEF_RELOAD_NEWGRF); + dump('t', GEF_TBTR_REPLACEMENT); + dump('D', GEF_DISASTER_VEH); + dump('c', GEF_TRAIN_CRASH); + dump('i', GEF_INDUSTRY_CREATE); + dump('j', GEF_INDUSTRY_DELETE); + dump('v', GEF_VIRT_TRAIN); + return b; +} diff --git a/src/event_logs.h b/src/event_logs.h new file mode 100644 index 0000000000..2cbf6b2dff --- /dev/null +++ b/src/event_logs.h @@ -0,0 +1,42 @@ +/* + * 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 event_logs.h Functions related to event logging. */ + +#ifndef EVENT_LOGS_H +#define EVENT_LOGS_H + +#include "core/enum_type.hpp" +#include + +enum GameEventFlags : uint32 { + GEF_COMPANY_DELETE = 1 << 0, ///< (d) A company has been deleted + GEF_COMPANY_MERGE = 1 << 1, ///< (m) A company has been bought by another + GEF_RELOAD_NEWGRF = 1 << 2, ///< (n) ReloadNewGRFData() has been called + GEF_TBTR_REPLACEMENT = 1 << 3, ///< (t) CMD_TEMPLATE_REPLACE_VEHICLE has been called + GEF_DISASTER_VEH = 1 << 4, ///< (D) A disaster vehicle exists or has been created + GEF_TRAIN_CRASH = 1 << 5, ///< (c) A train crash has occurred + GEF_INDUSTRY_CREATE = 1 << 6, ///< (i) An industry has been created (in game) + GEF_INDUSTRY_DELETE = 1 << 7, ///< (j) An industry has been deleted (in game) + GEF_VIRT_TRAIN = 1 << 8, ///< (v) A virtual train has been created +}; +DECLARE_ENUM_AS_BIT_SET(GameEventFlags) + +extern GameEventFlags _game_events_since_load; +extern GameEventFlags _game_events_overall; + +inline void RegisterGameEvents(GameEventFlags events) +{ + _game_events_since_load |= events; + _game_events_overall |= events; +} + +char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last); + +extern time_t _game_load_time; + +#endif /* EVENT_LOGS_H */ diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 59a1d9a399..dc6c9b6e71 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -43,6 +43,7 @@ #include "error.h" #include "cmd_helper.h" #include "string_func.h" +#include "event_logs.h" #include "table/strings.h" #include "table/industry_land.h" diff --git a/src/misc.cpp b/src/misc.cpp index 58eb04cb0d..2b4120a14c 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -38,6 +38,7 @@ #include "zoning.h" #include "cargopacket.h" #include "tbtr_template_vehicle_func.h" +#include "event_logs.h" #include "safeguards.h" diff --git a/src/openttd.cpp b/src/openttd.cpp index a61fe0bc8b..6e96cfbae7 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -80,6 +80,7 @@ #include "tbtr_template_vehicle_func.h" #include "debug_settings.h" #include "debug_desync.h" +#include "event_logs.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -114,11 +115,6 @@ bool _save_config = false; bool _request_newgrf_scan = false; NewGRFScanCallback *_request_newgrf_scan_callback = nullptr; -GameEventFlags _game_events_since_load; -GameEventFlags _game_events_overall; - -time_t _game_load_time; - SimpleChecksum64 _state_checksum; /** @@ -2021,21 +2017,3 @@ void GameLoop() SoundDriver::GetInstance()->MainLoop(); MusicLoop(); } - -char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last) -{ - if (b <= last) *b = 0; - auto dump = [&](char c, GameEventFlags ev) { - if (events & ev) b += seprintf(b, last, "%c", c); - }; - dump('d', GEF_COMPANY_DELETE); - dump('m', GEF_COMPANY_MERGE); - dump('n', GEF_RELOAD_NEWGRF); - dump('t', GEF_TBTR_REPLACEMENT); - dump('D', GEF_DISASTER_VEH); - dump('c', GEF_TRAIN_CRASH); - dump('i', GEF_INDUSTRY_CREATE); - dump('j', GEF_INDUSTRY_DELETE); - dump('v', GEF_VIRT_TRAIN); - return b; -} diff --git a/src/openttd.h b/src/openttd.h index 61296d2ca1..c183bcf7e8 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -79,32 +79,6 @@ DECLARE_ENUM_AS_BIT_SET(PauseMode) /** The current pause mode */ extern PauseMode _pause_mode; -enum GameEventFlags : uint32 { - GEF_COMPANY_DELETE = 1 << 0, ///< (d) A company has been deleted - GEF_COMPANY_MERGE = 1 << 1, ///< (m) A company has been bought by another - GEF_RELOAD_NEWGRF = 1 << 2, ///< (n) ReloadNewGRFData() has been called - GEF_TBTR_REPLACEMENT = 1 << 3, ///< (t) CMD_TEMPLATE_REPLACE_VEHICLE has been called - GEF_DISASTER_VEH = 1 << 4, ///< (D) A disaster vehicle exists or has been created - GEF_TRAIN_CRASH = 1 << 5, ///< (c) A train crash has occurred - GEF_INDUSTRY_CREATE = 1 << 6, ///< (i) An industry has been created (in game) - GEF_INDUSTRY_DELETE = 1 << 7, ///< (j) An industry has been deleted (in game) - GEF_VIRT_TRAIN = 1 << 8, ///< (v) A virtual train has been created -}; -DECLARE_ENUM_AS_BIT_SET(GameEventFlags) - -extern GameEventFlags _game_events_since_load; -extern GameEventFlags _game_events_overall; - -inline void RegisterGameEvents(GameEventFlags events) -{ - _game_events_since_load |= events; - _game_events_overall |= events; -} - -char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last); - -extern time_t _game_load_time; - void AskExitGame(); void AskExitToGameMenu(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index f03f999a21..65d0c57c4f 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -67,6 +67,7 @@ #include "../animated_tile.h" #include "../company_func.h" #include "../infrastructure_func.h" +#include "../event_logs.h" #include "saveload_internal.h" diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp index af7e8c4207..ce50cc5d8d 100644 --- a/src/saveload/misc_sl.cpp +++ b/src/saveload/misc_sl.cpp @@ -18,6 +18,7 @@ #include "../fios.h" #include "../road_type.h" #include "../core/checksum_func.hpp" +#include "../event_logs.h" #include "saveload.h" diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index df8650374c..e17d75bd46 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -45,6 +45,7 @@ #include "core/checksum_func.hpp" #include "debug_settings.h" #include "train_speed_adaptation.h" +#include "event_logs.h" #include "table/strings.h" #include "table/train_cmd.h" From 6f16655e6e87d682dfeb2452db6957e37ed51b6b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 20:54:12 +0100 Subject: [PATCH 25/43] Add "special events" log. Add console command, include in crash logs. --- src/console_cmds.cpp | 14 ++++++++ src/crashlog.cpp | 2 ++ src/economy.cpp | 6 ++++ src/event_logs.cpp | 67 ++++++++++++++++++++++++++++++++++++++ src/event_logs.h | 4 +++ src/misc.cpp | 1 + src/openttd.cpp | 1 + src/saveload/afterload.cpp | 1 + 8 files changed, 96 insertions(+) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 52b2bc4afc..62f1bdde70 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2250,6 +2250,19 @@ DEF_CONSOLE_CMD(ConDumpCommandLog) return true; } +DEF_CONSOLE_CMD(ConDumpSpecialEventsLog) +{ + if (argc == 0) { + IConsoleHelp("Dump log of special events."); + return true; + } + + char buffer[32768]; + DumpSpecialEventsLog(buffer, lastof(buffer)); + PrintLineByLine(buffer); + return true; +} + DEF_CONSOLE_CMD(ConDumpDesyncMsgLog) { if (argc == 0) { @@ -3470,6 +3483,7 @@ void IConsoleStdLibRegister() IConsole::CmdRegister("getfulldate", ConGetFullDate, nullptr, true); IConsole::CmdRegister("dump_command_log", ConDumpCommandLog, nullptr, true); + IConsole::CmdRegister("dump_special_events_log", ConDumpSpecialEventsLog, nullptr, true); IConsole::CmdRegister("dump_desync_msgs", ConDumpDesyncMsgLog, nullptr, true); IConsole::CmdRegister("dump_inflation", ConDumpInflation, nullptr, true); IConsole::CmdRegister("dump_cpdp_stats", ConDumpCpdpStats, nullptr, true); diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 63212d29a4..3664c0d165 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -411,6 +411,8 @@ char *CrashLog::LogCommandLog(char *buffer, const char *last) const { buffer = DumpCommandLog(buffer, last); buffer += seprintf(buffer, last, "\n"); + buffer = DumpSpecialEventsLog(buffer, last); + buffer += seprintf(buffer, last, "\n"); return buffer; } diff --git a/src/economy.cpp b/src/economy.cpp index 501db7006d..dcdc7e5932 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -590,6 +590,12 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) cur_company.Restore(); + if (new_owner != INVALID_OWNER) { + AppendSpecialEventsLogEntry(stdstr_fmt("Company merge: old: %u, new %u", old_owner, new_owner)); + } else { + AppendSpecialEventsLogEntry(stdstr_fmt("Company deletion: old: %u", old_owner)); + } + RegisterGameEvents(new_owner != INVALID_OWNER ? GEF_COMPANY_MERGE : GEF_COMPANY_DELETE); MarkWholeScreenDirty(); diff --git a/src/event_logs.cpp b/src/event_logs.cpp index 10bab41261..2b4bde0417 100644 --- a/src/event_logs.cpp +++ b/src/event_logs.cpp @@ -10,6 +10,10 @@ #include "stdafx.h" #include "event_logs.h" #include "string_func.h" +#include "date_func.h" +#include "company_func.h" +#include +#include #include "safeguards.h" @@ -35,3 +39,66 @@ char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last) dump('v', GEF_VIRT_TRAIN); return b; } + +struct SpecialEventLogEntry { + std::string msg; + Date date; + DateFract date_fract; + uint8 tick_skip_counter; + CompanyID current_company; + CompanyID local_company; + + SpecialEventLogEntry() { } + + SpecialEventLogEntry(std::string msg) + : msg(std::move(msg)), date(_date), date_fract(_date_fract), tick_skip_counter(_tick_skip_counter), + current_company(_current_company), local_company(_local_company) { } +}; + +struct SpecialEventLog { + std::array log; + unsigned int count = 0; + unsigned int next = 0; + + void Reset() + { + this->count = 0; + this->next = 0; + } +}; + +static SpecialEventLog _special_event_log; + +void AppendSpecialEventsLogEntry(std::string message) +{ + _special_event_log.log[_special_event_log.next] = SpecialEventLogEntry(std::move(message)); + _special_event_log.next = (_special_event_log.next + 1) % _special_event_log.log.size(); + _special_event_log.count++; +} + +char *DumpSpecialEventsLog(char *buffer, const char *last) +{ + const unsigned int count = std::min(_special_event_log.count, 64); + buffer += seprintf(buffer, last, "Special Events Log:\n Showing most recent %u of %u events\n", count, _special_event_log.count); + + unsigned int log_index = _special_event_log.next; + for (unsigned int i = 0 ; i < count; i++) { + if (log_index > 0) { + log_index--; + } else { + log_index = (uint)_special_event_log.log.size() - 1; + } + const SpecialEventLogEntry &entry = _special_event_log.log[log_index]; + + YearMonthDay ymd; + ConvertDateToYMD(entry.date, &ymd); + buffer += seprintf(buffer, last, " %3u | %4i-%02i-%02i, %2i, %3i | cc: %3u, lc: %3u | %s\n", + i, ymd.year, ymd.month + 1, ymd.day, entry.date_fract, entry.tick_skip_counter, (uint) entry.current_company, (uint) entry.local_company, entry.msg.c_str()); + } + return buffer; +} + +void ClearSpecialEventsLog() +{ + _special_event_log.Reset(); +} diff --git a/src/event_logs.h b/src/event_logs.h index 2cbf6b2dff..bdf3bdc8c4 100644 --- a/src/event_logs.h +++ b/src/event_logs.h @@ -39,4 +39,8 @@ char *DumpGameEventFlags(GameEventFlags events, char *b, const char *last); extern time_t _game_load_time; +void AppendSpecialEventsLogEntry(std::string message); +char *DumpSpecialEventsLog(char *buffer, const char *last); +void ClearSpecialEventsLog(); + #endif /* EVENT_LOGS_H */ diff --git a/src/misc.cpp b/src/misc.cpp index 2b4120a14c..69559daa45 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -79,6 +79,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin ViewportMapClearTunnelCache(); ClearCommandLog(); + ClearSpecialEventsLog(); ClearDesyncMsgLog(); _pause_mode = PM_UNPAUSED; diff --git a/src/openttd.cpp b/src/openttd.cpp index 6e96cfbae7..a094d5b6d7 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -457,6 +457,7 @@ static void ShutdownGame() ClearVehicleTickCaches(); InvalidateTemplateReplacementImages(); ClearCommandLog(); + ClearSpecialEventsLog(); ClearDesyncMsgLog(); _loaded_local_company = COMPANY_SPECTATOR; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 65d0c57c4f..6bd6da48cc 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -4031,6 +4031,7 @@ bool AfterLoadGame() void ReloadNewGRFData() { RegisterGameEvents(GEF_RELOAD_NEWGRF); + AppendSpecialEventsLogEntry("NewGRF reload"); RailTypeLabel rail_type_label_map[RAILTYPE_END]; for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { From ea9a65edcde4aae3a0e9e83fe8b2ade62d8782fe Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 21:01:03 +0100 Subject: [PATCH 26/43] Increase size of desync log message ring buffer --- src/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index 8bb3332052..568b90c17c 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -351,7 +351,7 @@ struct DesyncMsgLogEntry { }; struct DesyncMsgLog { - std::array log; + std::array log; unsigned int count = 0; unsigned int next = 0; From 07cc7da7fdef88bae124b33b9bb6ade4e83618f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Sun, 26 Sep 2021 18:41:41 +0200 Subject: [PATCH 27/43] Revert 7ca1793: Using Trackdir keyed node is not required, Exitdir keyed node still have the correct trackdir (#9576) (cherry picked from commit 11dece205c83b530d7ddaa1290efde04f4dfdeb9) --- src/pathfinder/yapf/yapf_ship.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index 15757c3327..e1fc8f5df7 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -337,16 +337,6 @@ struct CYapfShip1 : CYapfT > {}; -static inline bool RequireTrackdirKey() -{ - /* If the two curve penalties are not equal, then it is not possible to use the - * ExitDir keyed node list, as it there will be key overlap. Using Trackdir keyed - * nodes means potentially more paths are tested, which would be wasteful if it's - * not necessary. - */ - return _settings_game.pf.yapf.ship_curve45_penalty != _settings_game.pf.yapf.ship_curve90_penalty; -} - /** Ship controller helper - path finder invoker */ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, ShipPathCache &path_cache) { @@ -355,7 +345,7 @@ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir /* check if non-default YAPF type needed */ - if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) { + if (_settings_game.pf.yapf.disable_node_optimization) { pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir } @@ -373,7 +363,7 @@ bool YapfShipCheckReverse(const Ship *v) PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir /* check if non-default YAPF type needed */ - if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) { + if (_settings_game.pf.yapf.disable_node_optimization) { pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir } From fe8da3ae3a190cff0a9dcc552fe0825ca28c5850 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 21:37:42 +0100 Subject: [PATCH 28/43] Fix missing include in header --- src/crashlog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crashlog.h b/src/crashlog.h index a7c4a99d8d..dfbd7a02bd 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -12,6 +12,7 @@ #include "core/enum_type.hpp" #include +#include struct DesyncExtraInfo { enum Flags { From 92fc0f364b86cce92f2675ad2de8f5b6567313c8 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 4 Oct 2021 21:38:37 +0100 Subject: [PATCH 29/43] Version: Committing version data for tag: jgrpp-0.43.1 --- .ottdrev-vc | 4 ++-- README.md | 2 +- jgrpp-changelog.md | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.ottdrev-vc b/.ottdrev-vc index 2fe588c7b4..b5f76052e1 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.43.0 20210912 0 9d18a8869f43c09ac0ca90d1067695872b0188b6 1 0 2021 -c3b70543dc0c3b29485abf7b81a99d157e7e70bbe0fcf2fa30fd075f1eabd663 - +jgrpp-0.43.1 20211004 0 fe8da3ae3a190cff0a9dcc552fe0825ca28c5850 1 0 2021 +fbeb6b45e2e75ab56dd72ed06410f90827a489b5cf6b3236f3605b51c5747bdc - diff --git a/README.md b/README.md index e2dbb865a4..56a74337ce 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.43.0 +## JGR's Patchpack version 0.43.1 This is a collection of patches applied to [OpenTTD](http://www.openttd.org/) diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index 72b91efc7f..27ba1d612c 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,15 @@ * * * +### v0.43.1 (2021-10-04) +* Fix multi-aspect signal graphics not being immediately enabled for newly generated maps. +* Fix premature PBS reservations with using reverse at waypoint orders with timetabled wait times. +* Fix incorrect font heights when using custom fonts on MacOS. +* Fix crash when trying to place multitile objects at map edge. +* Routing restrictions: + * The reverse behind signal pathfinder now takes into account the train length to avoid reversing sidings which are too short. +* Add sort by maximum speed (fully loaded) to train list window. + ### v0.43.0 (2021-09-12) * Fix reversing a train inside a depot disrupting the PBS reservation of another train heading into the depot. * Fix ships being drawn with the wrong image direction after rotating in place in some circumstances. From 9299a29a5290ced047d4e26dd9f81aacd38975b3 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 29 May 2021 14:02:04 +0200 Subject: [PATCH 30/43] Fix: limit heightmap sizes to something reasonable to prevent crafted heightmaps to OOM-crash the game (cherry picked from commit 97c461d1e73f228dd366cd8f062701062edd9bd1) --- src/heightmap.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/heightmap.cpp b/src/heightmap.cpp index 7b070f4405..95a21d3a51 100644 --- a/src/heightmap.cpp +++ b/src/heightmap.cpp @@ -22,6 +22,40 @@ #include "safeguards.h" +/** + * Maximum number of pixels for one dimension of a heightmap image. + * Do not allow images for which the longest side is twice the maximum number of + * tiles along the longest side of the (tile) map. + */ +static const uint MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS = 2 * (1 << 16); + +/* + * Maximum size in pixels of the heightmap image. + */ +static const uint MAX_HEIGHTMAP_SIZE_PIXELS = 256 << 20; // ~256 million +/* + * When loading a PNG or BMP the 24 bpp variant requires at least 4 bytes per pixel + * of memory to load the data. Make sure the "reasonable" limit is well within the + * maximum amount of memory allocatable on 32 bit platforms. + */ +static_assert(MAX_HEIGHTMAP_SIZE_PIXELS < UINT32_MAX / 8); + +/** + * Check whether the loaded dimension of the heightmap image are considered valid enough + * to attempt to load the image. In other words, the width and height are not beyond the + * #MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS limit and the total number of pixels does not + * exceed #MAX_HEIGHTMAP_SIZE_PIXELS. A width or height less than 1 are disallowed too. + * @param width The width of the to be loaded height map. + * @param height The height of the to be loaded height map. + * @return True iff the dimensions are within the limits. + */ +static inline bool IsValidHeightmapDimension(size_t width, size_t height) +{ + return (uint64)width * height <= MAX_HEIGHTMAP_SIZE_PIXELS && + width > 0 && width <= MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS && + height > 0 && height <= MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS; +} + /** * Convert RGB colours to Grayscale using 29.9% Red, 58.7% Green, 11.4% Blue * (average luminosity formula, NTSC Colour Space) @@ -146,8 +180,7 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); - /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ - if ((uint64)width * height >= (size_t)-1) { + if (!IsValidHeightmapDimension(width, height)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); @@ -255,8 +288,7 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map) return false; } - /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ - if ((uint64)info.width * info.height >= (size_t)-1 / (info.bpp == 24 ? 3 : 1)) { + if (!IsValidHeightmapDimension(info.width, info.height)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(f); BmpDestroyData(&data); @@ -295,6 +327,8 @@ static void GrayscaleToMapHeights(uint img_width, uint img_height, byte *map) { /* Defines the detail of the aspect ratio (to avoid doubles) */ const uint num_div = 16384; + /* Ensure multiplication with num_div does not cause overflows. */ + static_assert(num_div <= std::numeric_limits::max() / MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS); uint width, height; uint row, col; From 3411203e5da968812d44bf18612d52c143f30e95 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 8 Jun 2021 20:30:44 +0200 Subject: [PATCH 31/43] Fix: compatible NewGRFs in crash-log reported wrong md5 (#9340) The text suggests it reports the original md5, but it does in fact report the replaced md5. Now it reports both. (cherry picked from commit f997eb6ca4177b577387306b4c15ec4815f0f13c) --- src/saveload/afterload.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 6bd6da48cc..5d5cb7597c 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -444,9 +444,11 @@ static void CDECL HandleSavegameLoadCrash(int signum) for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (HasBit(c->flags, GCF_COMPATIBLE)) { const GRFIdentifier *replaced = GetOverriddenIdentifier(c); - char buf[40]; - md5sumToString(buf, lastof(buf), replaced->md5sum); - p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" with same GRF ID instead.\n", BSWAP32(c->ident.grfid), buf, c->filename); + char original_md5[40]; + char replaced_md5[40]; + md5sumToString(original_md5, lastof(original_md5), c->original_md5sum); + md5sumToString(replaced_md5, lastof(replaced_md5), replaced->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" (checksum %s) with same GRF ID instead.\n", BSWAP32(c->ident.grfid), original_md5, c->filename, replaced_md5); } if (c->status == GCS_NOT_FOUND) { char buf[40]; From 563884105fbdce9cf5b3837be277e695e5ac0ab4 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 27 May 2021 17:56:39 +0100 Subject: [PATCH 32/43] Change: by default, make "unload all" leave stations empty (#9301) (cherry picked from commit 76484833643c1aff90d41eb01de70f7e8ba0ceb9) --- src/fileio.cpp | 29 +++++++++++++++++++++++++---- src/fileio_func.h | 2 +- src/openttd.cpp | 10 +++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 72f1809244..d5b1af809c 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -79,10 +79,22 @@ static bool IsValidSearchPath(Searchpath sp) return sp < _searchpaths.size() && !_searchpaths[sp].empty(); } -static void FillValidSearchPaths() +static void FillValidSearchPaths(bool only_local_path) { _valid_searchpaths.clear(); for (Searchpath sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) { + if (only_local_path) { + switch (sp) { + case SP_WORKING_DIR: // Can be influence by "-c" option. + case SP_BINARY_DIR: // Most likely contains all the language files. + case SP_AUTODOWNLOAD_DIR: // Otherwise we cannot download in-game content. + break; + + default: + continue; + } + } + if (IsValidSearchPath(sp)) _valid_searchpaths.emplace_back(sp); } } @@ -958,11 +970,12 @@ std::string _personal_dir; * fill all other paths (save dir, autosave dir etc) and * make the save and scenario directories. * @param exe the path from the current path to the executable + * @param only_local_path Whether we shouldn't fill searchpaths with global folders. */ -void DeterminePaths(const char *exe) +void DeterminePaths(const char *exe, bool only_local_path) { DetermineBasePaths(exe); - FillValidSearchPaths(); + FillValidSearchPaths(only_local_path); #ifdef USE_XDG std::string config_home; @@ -1029,6 +1042,13 @@ void DeterminePaths(const char *exe) /* We are using the XDG configuration home for the config file, * then store the rest in the XDG data home folder. */ _personal_dir = _searchpaths[SP_PERSONAL_DIR_XDG]; + if (only_local_path) { + /* In case of XDG and we only want local paths and we detected that + * the user either manually indicated the XDG path or didn't use + * "-c" option, we change the working-dir to the XDG personal-dir, + * as this is most likely what the user is expecting. */ + _searchpaths[SP_WORKING_DIR] = _searchpaths[SP_PERSONAL_DIR_XDG]; + } } else #endif { @@ -1053,8 +1073,9 @@ void DeterminePaths(const char *exe) /* If we have network we make a directory for the autodownloading of content */ _searchpaths[SP_AUTODOWNLOAD_DIR] = _personal_dir + "content_download" PATHSEP; + DEBUG(misc, 4, "%s added as search path", _searchpaths[SP_AUTODOWNLOAD_DIR].c_str()); FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); - FillValidSearchPaths(); + FillValidSearchPaths(only_local_path); /* Create the directory for each of the types of content */ const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR }; diff --git a/src/fileio_func.h b/src/fileio_func.h index f84acd3a46..5c02b2aaf5 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -27,7 +27,7 @@ const char *FiosGetScreenshotDir(); void SanitizeFilename(char *filename); void AppendPathSeparator(std::string &buf); -void DeterminePaths(const char *exe); +void DeterminePaths(const char *exe, bool only_local_path); std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize); bool FileExists(const std::string &filename); bool ExtractTar(const std::string &tar_filename, Subdirectory subdir); diff --git a/src/openttd.cpp b/src/openttd.cpp index a094d5b6d7..4317694d96 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -249,6 +249,7 @@ static void ShowHelp() " -M music_set = Force the music set (see below)\n" " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" " -x = Never save configuration changes to disk\n" + " -X = Don't use global folders to search for files\n" " -q savegame = Write some information about the savegame and exit\n" " -Z = Write detailed version information and exit\n" "\n", @@ -681,6 +682,7 @@ static const OptionData _options[] = { GETOPT_SHORT_VALUE('G'), GETOPT_SHORT_VALUE('c'), GETOPT_SHORT_NOVAL('x'), + GETOPT_SHORT_NOVAL('X'), GETOPT_SHORT_VALUE('q'), GETOPT_SHORT_VALUE('K'), GETOPT_SHORT_NOVAL('h'), @@ -710,6 +712,7 @@ int openttd_main(int argc, char *argv[]) std::unique_ptr scanner(new AfterNewGRFScan()); bool dedicated = false; char *debuglog_conn = nullptr; + bool only_local_path = false; extern bool _dedicated_forks; _dedicated_forks = false; @@ -792,7 +795,7 @@ int openttd_main(int argc, char *argv[]) break; case 'q': case 'K': { - DeterminePaths(argv[0]); + DeterminePaths(argv[0], only_local_path); if (StrEmpty(mgo.opt)) { ret = 1; return ret; @@ -833,6 +836,7 @@ int openttd_main(int argc, char *argv[]) CrashLog::VersionInfoLog(); return ret; } + case 'X': only_local_path = true; break; case 'h': i = -2; // Force printing of help. break; @@ -846,7 +850,7 @@ int openttd_main(int argc, char *argv[]) * * The next two functions are needed to list the graphics sets. We can't do them earlier * because then we cannot show it on the debug console as that hasn't been configured yet. */ - DeterminePaths(argv[0]); + DeterminePaths(argv[0], only_local_path); TarScanner::DoScan(TarScanner::BASESET); BaseGraphics::FindSets(); BaseSounds::FindSets(); @@ -855,7 +859,7 @@ int openttd_main(int argc, char *argv[]) return ret; } - DeterminePaths(argv[0]); + DeterminePaths(argv[0], only_local_path); TarScanner::DoScan(TarScanner::BASESET); if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision); From 364ce76d51cd8dda40d8b26fdf30c5488e8e6f44 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 10 Jun 2021 20:11:50 +0200 Subject: [PATCH 33/43] Change: allow pause/unpause console command in single player too (#9342) (cherry picked from commit 849a10520cc26a98d91981a7705775a2481beef2) --- src/console_cmds.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 62f1bdde70..27635eae96 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -174,11 +174,24 @@ DEF_CONSOLE_HOOK(ConHookNoNetwork) return CHR_ALLOW; } +/** + * Check if are either in singleplayer or a server. + * @return True iff we are either in singleplayer or a server. + */ +DEF_CONSOLE_HOOK(ConHookServerOrNoNetwork) +{ + if (_networking && !_network_server) { + if (echo) IConsoleError("This command is only available to a network server."); + return CHR_DISALLOW; + } + return CHR_ALLOW; +} + DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) { if (_settings_client.gui.newgrf_developer_tools) { if (_game_mode == GM_MENU) { - if (echo) IConsoleError("This command is only available in game and editor."); + if (echo) IConsoleError("This command is only available in-game and in the editor."); return CHR_DISALLOW; } return ConHookNoNetwork(echo); @@ -223,7 +236,7 @@ DEF_CONSOLE_CMD(ConResetEnginePool) } if (_game_mode == GM_MENU) { - IConsoleError("This command is only available in game and editor."); + IConsoleError("This command is only available in-game and in the editor."); return true; } @@ -684,6 +697,11 @@ DEF_CONSOLE_CMD(ConPauseGame) return true; } + if (_game_mode == GM_MENU) { + IConsoleError("This command is only available in-game and in the editor."); + return true; + } + if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) { DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); if (!_networking) IConsolePrint(CC_DEFAULT, "Game paused."); @@ -701,6 +719,11 @@ DEF_CONSOLE_CMD(ConUnpauseGame) return true; } + if (_game_mode == GM_MENU) { + IConsoleError("This command is only available in-game and in the editor."); + return true; + } + if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) { DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); if (!_networking) IConsolePrint(CC_DEFAULT, "Game unpaused."); @@ -3430,8 +3453,8 @@ void IConsoleStdLibRegister() IConsole::CmdRegister("unban", ConUnBan, ConHookServerOnly); IConsole::CmdRegister("banlist", ConBanList, ConHookServerOnly); - IConsole::CmdRegister("pause", ConPauseGame, ConHookServerOnly); - IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOnly); + IConsole::CmdRegister("pause", ConPauseGame, ConHookServerOrNoNetwork); + IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOrNoNetwork); IConsole::CmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork); IConsole::AliasRegister("company_password", "company_pw %+"); From 0a7a4e06ad4c7635c149c924a7d52c7066d0c982 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 10 Jun 2021 19:34:53 +0200 Subject: [PATCH 34/43] Add: adhere the autosave_on_exit setting for Null videodriver (#9343) This is especially useful for automated-testing, to make a save when the game quits while using "-vnull:ticks=N". (cherry picked from commit 37ae6b8ae3762ddccdeb96a178b2634791e2bbe0) --- src/video/null_v.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp index 78b660258f..754b3c0ef0 100644 --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../gfx_func.h" #include "../blitter/factory.hpp" +#include "../saveload/saveload.h" #include "../window_func.h" #include "../thread.h" #include "null_v.h" @@ -63,6 +64,12 @@ void VideoDriver_Null::MainLoop() ::UpdateWindows(); } } + + /* If requested, make a save just before exit. The normal exit-flow is + * not triggered from this driver, so we have to do this manually. */ + if (_settings_client.gui.autosave_on_exit) { + DoExitSave(); + } } bool VideoDriver_Null::ChangeResolution(int w, int h) { return false; } From 0f05fc8573df96140115506c0c1c0e221afc00af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Fri, 11 Jun 2021 16:40:04 +0200 Subject: [PATCH 35/43] Fix: [Script] doxygen_filter is very strict about DOXYGEN_API usage (#9351) (cherry picked from commit ee5f23382d551bedcc998ba7aaf92333885c21d4) --- src/script/api/script_priorityqueue.hpp | 2 +- src/script/api/script_text.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/script/api/script_priorityqueue.hpp b/src/script/api/script_priorityqueue.hpp index 5f8718e424..517f6ab0bd 100644 --- a/src/script/api/script_priorityqueue.hpp +++ b/src/script/api/script_priorityqueue.hpp @@ -76,7 +76,7 @@ public: SQInteger Peek(HSQUIRRELVM vm); SQInteger Exists(HSQUIRRELVM vm); SQInteger Clear(HSQUIRRELVM vm); -#endif +#endif /* DOXYGEN_API */ /** * Check if the queue is empty. diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 445f6ce787..204aa3ea6a 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -88,7 +88,7 @@ public: * @param ... Optional arguments for this string. */ ScriptText(StringID string, ...); -#endif +#endif /* DOXYGEN_API */ ~ScriptText(); #ifndef DOXYGEN_API From d46c764d60809d918fb56a5f8b5336033f370592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guilloux?= Date: Fri, 11 Jun 2021 16:59:19 +0200 Subject: [PATCH 36/43] Fix 4079c47: Missed a file when removing generated .sq files from the repo (#9350) (cherry picked from commit 16ebf7861f2b8fce6f1c44b0666bb8794a39abbb) --- .../template/template_priorityqueue.hpp.sq | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 src/script/api/template/template_priorityqueue.hpp.sq diff --git a/src/script/api/template/template_priorityqueue.hpp.sq b/src/script/api/template/template_priorityqueue.hpp.sq deleted file mode 100644 index 14c63324fb..0000000000 --- a/src/script/api/template/template_priorityqueue.hpp.sq +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 . - */ - -/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ - -#include "../script_priorityqueue.hpp" - -namespace SQConvert { - /* Allow ScriptPriorityQueue to be used as Squirrel parameter */ - template <> inline ScriptPriorityQueue *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptPriorityQueue *)instance; } - template <> inline ScriptPriorityQueue &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptPriorityQueue *)instance; } - template <> inline const ScriptPriorityQueue *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptPriorityQueue *)instance; } - template <> inline const ScriptPriorityQueue &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptPriorityQueue *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptPriorityQueue *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "PriorityQueue", res, nullptr, DefSQDestructorCallback, true); return 1; } -} // namespace SQConvert From 057e858d32d4eede385d369a3f8ad0ab036376ad Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 12 Jun 2021 16:45:26 +0200 Subject: [PATCH 37/43] Fix #9353: [Script] Garbage collecting on priority queues could crash the game (cherry picked from commit 71f3c35288e0b7a357918b285d9fbfa0bc8060dc) --- src/script/script_instance.cpp | 7 +++++-- src/script/script_instance.hpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index dce1f783fd..610f02cfa6 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -278,9 +278,12 @@ void ScriptInstance::GameLoop() } } -void ScriptInstance::CollectGarbage() const +void ScriptInstance::CollectGarbage() { - if (this->is_started && !this->IsDead()) this->engine->CollectGarbage(); + if (this->is_started && !this->IsDead()) { + ScriptObject::ActiveInstance active(this); + this->engine->CollectGarbage(); + } } /* static */ void ScriptInstance::DoCommandReturn(ScriptInstance *instance) diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index b6f0eb3d20..5f41d37989 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -68,7 +68,7 @@ public: /** * Let the VM collect any garbage. */ - void CollectGarbage() const; + void CollectGarbage(); /** * Get the storage of this script. From 3e78624965d5b99adde9e341887cfa3b23d7ff03 Mon Sep 17 00:00:00 2001 From: TELK Date: Sun, 13 Jun 2021 17:06:50 +0900 Subject: [PATCH 38/43] Fix #9362: Hover in online players window was slightly too big (#9364) This causes graphical glitches at the bottom of the window. (cherry picked from commit 2d0abf5a7643afb2b37ca8902d13f1df5c14f5ee) --- src/network/network_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 844326775b..1e20e06e7c 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -2352,7 +2352,7 @@ public: if (this->hover_index >= 0) { uint offset = this->hover_index * this->line_height; - GfxFillRect(r.left + 2, r.top + offset, r.right - 1, r.top + offset + this->line_height - 1, GREY_SCALE(9)); + GfxFillRect(r.left + 2, r.top + offset, r.right - 1, r.top + offset + this->line_height - 2, GREY_SCALE(9)); } NetworkClientInfo *own_ci = NetworkClientInfo::GetByClientID(_network_own_client_id); From 573ab48e9cf9bf76bc1ef332602791a973380dca Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 13 Jun 2021 13:48:40 +0200 Subject: [PATCH 39/43] Fix 81062163: for (really) old games, station bus/truck station cache was not updated (#9366) (cherry picked from commit 1e432fbd7124a617374e3db56f41a26541890ce5) --- src/saveload/afterload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 5d5cb7597c..a981de5620 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -1722,7 +1722,7 @@ bool AfterLoadGame() c->avail_roadtypes = GetCompanyRoadTypes(c->index); } - if (!IsSavegameVersionBefore(SLV_27)) AfterLoadStations(); + AfterLoadStations(); /* Time starts at 0 instead of 1920. * Account for this in older games by adding an offset */ From 441ff7e43650a04cfbde36f00d6f5c0a9be37e97 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 17 Jun 2021 17:58:59 +0100 Subject: [PATCH 40/43] Fix: thread safety issue during exiting the game (#9380) _exit_game is read by the draw-thread to know when to exit, but most of the time written by the game-thread. (cherry picked from commit c12a152ec972309a87ab1637091990520ce9c123) --- src/gfx.cpp | 2 +- src/openttd.h | 3 ++- src/video/null_v.cpp | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gfx.cpp b/src/gfx.cpp index fc9d1455cd..7c5982e3e8 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -48,7 +48,7 @@ bool _right_button_clicked; ///< Is right mouse button clicked? DrawPixelInfo _screen; bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) bool _check_special_modes; -bool _exit_game; +std::atomic _exit_game; GameMode _game_mode; SwitchMode _switch_mode; ///< The next mainloop command. PauseMode _pause_mode; diff --git a/src/openttd.h b/src/openttd.h index c183bcf7e8..dc03efd1f8 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -10,6 +10,7 @@ #ifndef OPENTTD_H #define OPENTTD_H +#include #include "core/enum_type.hpp" /** Mode which defines the state of the game. */ @@ -57,7 +58,7 @@ enum ExtraDisplayOptions { extern GameMode _game_mode; extern SwitchMode _switch_mode; extern bool _check_special_modes; -extern bool _exit_game; +extern std::atomic _exit_game; extern bool _save_config; /** Modes of pausing we've got */ diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp index 754b3c0ef0..bec6f6a9e1 100644 --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -15,12 +15,14 @@ #include "../thread.h" #include "null_v.h" +#include + #include "../safeguards.h" /** Factory for the null video driver. */ static FVideoDriver_Null iFVideoDriver_Null; -extern bool _exit_game; +extern std::atomic _exit_game; const char *VideoDriver_Null::Start(const StringList &parm) { From 0550ca0854d18860f23de7772ba0887c771b8c40 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 17 Jun 2021 20:10:40 +0200 Subject: [PATCH 41/43] Fix: on startup, NewGRF scan could case race-condition (#9382) Creating a thread was not thread-safe. The irony. The video-driver has a function GameLoopPause() which first checks if the thread is the game-thread or not. For this it needs access to this->game_thread. This variable is set in StartNewThread(). However, due to timing, it is well possible GameLoopPause() is called from the thread well before this->game_thread is assigned. And so we have a race-condition! Simply solve this by preventing a thread to start till we are done with our bookkeeping. (cherry picked from commit b45c006ab9bdfb92fa6be66dcfa00099adbb85a8) --- src/thread.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/thread.h b/src/thread.h index 66581b7573..55b13ee5d5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -14,6 +14,7 @@ #include "crashlog.h" #include #include +#include #if defined(__MINGW32__) #include "3rdparty/mingw-std-threads/mingw.thread.h" #endif @@ -97,7 +98,17 @@ inline bool StartNewThread(std::thread *thr, const char *name, TFn&& _Fx, TArgs& { #ifndef NO_THREADS try { + static std::mutex thread_startup_mutex; + std::lock_guard lock(thread_startup_mutex); + std::thread t([] (const char *name, TFn&& F, TArgs&&... A) { + /* Delay starting the thread till the main thread is finished + * with the administration. This prevent race-conditions on + * startup. */ + { + std::lock_guard lock(thread_startup_mutex); + } + SetCurrentThreadName(name); PerThreadSetup(); CrashLog::InitThread(); From 48b287a22f3c93587c28803073b97d4f4cb14a20 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Thu, 17 Jun 2021 23:08:49 +0100 Subject: [PATCH 42/43] Fix #9358: Don't skip empty files in tar (#9367) (cherry picked from commit 1e6a2163a5ca5fe0e17fbd9adef23571f2c36a8a) --- src/fileio.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index d5b1af809c..7c2aaadf69 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -547,9 +547,6 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co switch (th.typeflag) { case '\0': case '0': { // regular file - /* Ignore empty files */ - if (skip == 0) break; - if (strlen(name) == 0) break; /* Store this entry in the list */ From 32571a0ccd9b13979c50926255c57d4e77c93efc Mon Sep 17 00:00:00 2001 From: PeterN Date: Thu, 17 Jun 2021 23:34:59 +0100 Subject: [PATCH 43/43] Fix: Wrong cargo line position in IndustryCargo window. (#9383) Resolved by changing calculation to determine the offset based on centring the cargo lines in the available space. (cherry picked from commit ce7ef4d824b9e6cd852826b6fcc41263487ebd5e) --- src/industry_gui.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 1148e1acd6..fd6f07fddc 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -2022,11 +2022,7 @@ struct CargoesField { assert(this->type == CFT_CARGO); int n = this->u.cargo.num_cargoes; - if (n % 2 == 0) { - return xpos + cargo_field_width / 2 - (CargoesField::cargo_line.width + CargoesField::cargo_space.width / 2) * (n / 2); - } else { - return xpos + cargo_field_width / 2 - CargoesField::cargo_line.width / 2 - (CargoesField::cargo_line.width + CargoesField::cargo_space.width) * (n / 2); - } + return xpos + cargo_field_width / 2 - (CargoesField::cargo_line.width * n + CargoesField::cargo_space.width * (n - 1)) / 2; } /**