From 5059e23ed5e83542e26581cd1b9a9e5863b5b6f6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 30 Mar 2023 09:34:26 +0100 Subject: [PATCH 01/58] Revert 8fa61533: "Fix 30ae072: when a road type is hidden, towns may not build them even when that flag is set" This reverts commit 8fa61533f041b16497282107afa600e919ba7154. --- src/road.cpp | 9 ++++++++- src/road.h | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/road.cpp b/src/road.cpp index b5c4963333..87b1c6a065 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -112,7 +112,14 @@ bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype) { if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) { const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype); - return rti->label != 0 && (rti->flags & ROTFB_HIDDEN) == 0; + if (rti->label == 0) return false; + + /* + * Do not allow building hidden road types, except when a town may build it. + * The GS under deity mode, as well as anybody in the editor builds roads that are + * owned by towns. So if a town may build it, it should be buildable by them too. + */ + return (rti->flags & ROTFB_HIDDEN) == 0 || (rti->flags & ROTFB_TOWN_BUILD) != 0; } else { const Company *c = Company::GetIfValid(company); if (c == nullptr) return false; diff --git a/src/road.h b/src/road.h index a9ff16f656..6872a8ca5e 100644 --- a/src/road.h +++ b/src/road.h @@ -39,14 +39,14 @@ enum RoadTypeFlags { ROTF_NO_LEVEL_CROSSING, ///< Bit number for disabling level crossing ROTF_NO_HOUSES, ///< Bit number for setting this roadtype as not house friendly ROTF_HIDDEN, ///< Bit number for hidden from construction. - ROTF_TOWN_BUILD, ///< Bit number for allowing towns to build this roadtype. Does not override ROTF_HIDDEN. + ROTF_TOWN_BUILD, ///< Bit number for allowing towns to build this roadtype. ROTFB_NONE = 0, ///< All flags cleared. ROTFB_CATENARY = 1 << ROTF_CATENARY, ///< Value for drawing a catenary. ROTFB_NO_LEVEL_CROSSING = 1 << ROTF_NO_LEVEL_CROSSING, ///< Value for disabling a level crossing. ROTFB_NO_HOUSES = 1 << ROTF_NO_HOUSES, ///< Value for for setting this roadtype as not house friendly. ROTFB_HIDDEN = 1 << ROTF_HIDDEN, ///< Value for hidden from construction. - ROTFB_TOWN_BUILD = 1 << ROTF_TOWN_BUILD, ///< Value for allowing towns to build this roadtype. Does not override ROTFB_HIDDEN. + ROTFB_TOWN_BUILD = 1 << ROTF_TOWN_BUILD, ///< Value for allowing towns to build this roadtype. }; DECLARE_ENUM_AS_BIT_SET(RoadTypeFlags) From 726d05b22b65401cea8f22d9f3eb3f17bcc81d52 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 30 Mar 2023 12:08:58 +0100 Subject: [PATCH 02/58] Fix: Don't list unavailable road types for game scripts. --- src/script/api/script_roadtypelist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/api/script_roadtypelist.cpp b/src/script/api/script_roadtypelist.cpp index 5d2ad8ae6a..e1728553be 100644 --- a/src/script/api/script_roadtypelist.cpp +++ b/src/script/api/script_roadtypelist.cpp @@ -18,6 +18,6 @@ ScriptRoadTypeList::ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts) EnforceDeityOrCompanyModeValid_Void(); for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { if (!HasBit(rtts, GetRoadTramType(rt))) continue; - if (ScriptCompanyMode::IsDeity() || ::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt); + if (::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt); } } From 1a93618bd16461fc4b276a38cc9b5ff525127c89 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 30 Mar 2023 12:09:38 +0100 Subject: [PATCH 03/58] Fix: Road type is not available before its introduction date. --- src/road.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/road.cpp b/src/road.cpp index 87b1c6a065..1d3ec4d43d 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -114,6 +114,9 @@ bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype) const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype); if (rti->label == 0) return false; + /* Not yet introduced at this date. */ + if (IsInsideMM(rti->introduction_date, 0, MAX_DATE) && rti->introduction_date > TimerGameCalendar::date) return false; + /* * Do not allow building hidden road types, except when a town may build it. * The GS under deity mode, as well as anybody in the editor builds roads that are From 72c7536325e24c0dc9a56031f7c840d9b2648347 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Fri, 12 May 2023 21:41:36 +0200 Subject: [PATCH 04/58] Codechange: Use a dedicated variable for disaster vehicle action state. (#10798) --- src/disaster_vehicle.cpp | 66 +++++++++++++++++------------------ src/disaster_vehicle.h | 1 + src/saveload/afterload.cpp | 4 +-- src/saveload/oldloader_sl.cpp | 4 +++ src/saveload/saveload.h | 1 + src/saveload/vehicle_sl.cpp | 5 +-- 6 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 571b403b68..8cf825ba47 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -17,7 +17,7 @@ * that handles the vehicle's ticks. *
  • Run the disaster vehicles each tick until their target has been reached, * this happens in the DisasterTick_XXX() functions. In here, a vehicle's - * state is kept by v->current_order.dest variable. Each achieved sub-target + * state is kept by v->state variable. Each achieved sub-target * will increase this value, and the last one will remove the disaster itself * */ @@ -168,7 +168,7 @@ DisasterVehicle::DisasterVehicle(int x, int y, Direction direction, DisasterSubT this->UpdateDeltaXY(); this->owner = OWNER_NONE; this->image_override = 0; - this->current_order.Free(); + this->state = 0; this->UpdateImage(); this->UpdatePositionAndViewport(); @@ -214,7 +214,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z) } /** - * Zeppeliner handling, v->current_order.dest states: + * Zeppeliner handling, v->state states: * 0: Zeppeliner initialization has found a small airport, go there and crash * 1: Create crash and animate falling down for extra dramatic effect * 2: Create more smoke and leave debris on ground @@ -225,24 +225,24 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v) { v->tick_counter++; - if (v->current_order.GetDestination() < 2) { + if (v->state < 2) { if (HasBit(v->tick_counter, 0)) return true; GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); - if (v->current_order.GetDestination() == 1) { + if (v->state == 1) { if (++v->age == 38) { - v->current_order.SetDestination(2); + v->state = 2; v->age = 0; } if (GB(v->tick_counter, 0, 3) == 0) CreateEffectVehicleRel(v, 0, -17, 2, EV_CRASH_SMOKE); - } else if (v->current_order.GetDestination() == 0) { + } else if (v->state == 0) { if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { - v->current_order.SetDestination(1); + v->state = 1; v->age = 0; SetDParam(0, GetStationIndex(v->tile)); @@ -259,7 +259,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v) return true; } - if (v->current_order.GetDestination() > 2) { + if (v->state > 2) { if (++v->age <= 13320) return true; if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { @@ -296,7 +296,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v) EV_EXPLOSION_SMALL); } } else if (v->age == 350) { - v->current_order.SetDestination(3); + v->state = 3; v->age = 0; } @@ -308,7 +308,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v) } /** - * (Small) Ufo handling, v->current_order.dest states: + * (Small) Ufo handling, v->state states: * 0: Fly around to the middle of the map, then randomly, after a while target a road vehicle * 1: Home in on a road vehicle and crash it >:) * If not road vehicle was found, only state 0 is used and Ufo disappears after a while @@ -317,7 +317,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) { v->image_override = (HasBit(++v->tick_counter, 3)) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT; - if (v->current_order.GetDestination() == 0) { + if (v->state == 0) { /* Fly around randomly */ int x = TileX(v->dest_tile) * TILE_SIZE; int y = TileY(v->dest_tile) * TILE_SIZE; @@ -331,7 +331,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) v->dest_tile = RandomTile(); return true; } - v->current_order.SetDestination(1); + v->state = 1; uint n = 0; // Total number of targetable road vehicles. for (const RoadVehicle *u : RoadVehicle::Iterate()) { @@ -410,7 +410,7 @@ static void DestructIndustry(Industry *i) } /** - * Aircraft handling, v->current_order.dest states: + * Aircraft handling, v->state states: * 0: Fly towards the targeted industry * 1: If within 15 tiles, fire away rockets and destroy industry * 2: Industry explosions @@ -425,7 +425,7 @@ static void DestructIndustry(Industry *i) static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, bool leave_at_top, StringID news_message, IndustryBehaviour industry_flag) { v->tick_counter++; - v->image_override = (v->current_order.GetDestination() == 1 && HasBit(v->tick_counter, 2)) ? image_override : 0; + v->image_override = (v->state == 1 && HasBit(v->tick_counter, 2)) ? image_override : 0; GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); @@ -435,7 +435,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, boo return false; } - if (v->current_order.GetDestination() == 2) { + if (v->state == 2) { if (GB(v->tick_counter, 0, 2) == 0) { Industry *i = Industry::Get(v->dest_tile); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid int x = TileX(i->location.tile) * TILE_SIZE; @@ -448,11 +448,11 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, boo GB(r, 12, 4), EV_EXPLOSION_SMALL); - if (++v->age >= 55) v->current_order.SetDestination(3); + if (++v->age >= 55) v->state = 3; } - } else if (v->current_order.GetDestination() == 1) { + } else if (v->state == 1) { if (++v->age == 112) { - v->current_order.SetDestination(2); + v->state = 2; v->age = 0; Industry *i = Industry::Get(v->dest_tile); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid @@ -462,7 +462,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, boo AddIndustryNewsItem(news_message, NT_ACCIDENT, i->index); if (_settings_client.sound.disaster) SndPlayTileFx(SND_12_EXPLOSION, i->location.tile); } - } else if (v->current_order.GetDestination() == 0) { + } else if (v->state == 0) { int x = v->x_pos + ((leave_at_top ? -15 : 15) * TILE_SIZE); int y = v->y_pos; @@ -475,7 +475,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, boo v->dest_tile = ind; if (GetIndustrySpec(Industry::Get(ind)->type)->behaviour & industry_flag) { - v->current_order.SetDestination(1); + v->state = 1; v->age = 0; } } @@ -510,7 +510,7 @@ static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v) } /** - * (Big) Ufo handling, v->current_order.dest states: + * (Big) Ufo handling, v->state states: * 0: Fly around to the middle of the map, then randomly for a while and home in on a piece of rail * 1: Land there and breakdown all trains in a radius of 12 tiles; and now we wait... * because as soon as the Ufo lands, a fighter jet, a Skyranger, is called to clear up the mess @@ -519,7 +519,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) { v->tick_counter++; - if (v->current_order.GetDestination() == 1) { + if (v->state == 1) { int x = TileX(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2; int y = TileY(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2; if (Delta(v->x_pos, x) + Delta(v->y_pos, y) >= 8) { @@ -542,7 +542,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) return true; } - v->current_order.SetDestination(2); + v->state = 2; for (Vehicle *target : Vehicle::Iterate()) { if (target->IsGroundVehicle()) { @@ -564,7 +564,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) DisasterVehicle *u = new DisasterVehicle(-6 * (int)TILE_SIZE, v->y_pos, DIR_SW, ST_BIG_UFO_DESTROYER, v->index); DisasterVehicle *w = new DisasterVehicle(-6 * (int)TILE_SIZE, v->y_pos, DIR_SW, ST_BIG_UFO_DESTROYER_SHADOW); u->SetNext(w); - } else if (v->current_order.GetDestination() == 0) { + } else if (v->state == 0) { int x = TileX(v->dest_tile) * TILE_SIZE; int y = TileY(v->dest_tile) * TILE_SIZE; if (Delta(x, v->x_pos) + Delta(y, v->y_pos) >= (int)TILE_SIZE) { @@ -578,7 +578,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) v->dest_tile = RandomTile(); return true; } - v->current_order.SetDestination(1); + v->state = 1; const auto is_valid_target = [](const Train *t) { return t->IsFrontEngine() // Only the engines @@ -614,7 +614,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) } /** - * Skyranger destroying (Big) Ufo handling, v->current_order.dest states: + * Skyranger destroying (Big) Ufo handling, v->state states: * 0: Home in on landed Ufo and shoot it down */ static bool DisasterTick_Big_Ufo_Destroyer(DisasterVehicle *v) @@ -629,10 +629,10 @@ static bool DisasterTick_Big_Ufo_Destroyer(DisasterVehicle *v) return false; } - if (v->current_order.GetDestination() == 0) { + if (v->state == 0) { Vehicle *u = Vehicle::Get(v->big_ufo_destroyer_target); if (Delta(v->x_pos, u->x_pos) > (int)TILE_SIZE) return true; - v->current_order.SetDestination(1); + v->state = 1; CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, u); @@ -660,7 +660,7 @@ static bool DisasterTick_Big_Ufo_Destroyer(DisasterVehicle *v) } /** - * Submarine, v->current_order.dest states: + * Submarine, v->state states: * Unused, just float around aimlessly and pop up at different places, turning around */ static bool DisasterTick_Submarine(DisasterVehicle *v) @@ -961,7 +961,7 @@ void ReleaseDisastersTargetingIndustry(IndustryID i) /* primary disaster vehicles that have chosen target */ if (v->subtype == ST_AIRPLANE || v->subtype == ST_HELICOPTER) { /* if it has chosen target, and it is this industry (yes, dest_tile is IndustryID here), set order to "leaving map peacefully" */ - if (v->current_order.GetDestination() > 0 && v->dest_tile == (uint32)i) v->current_order.SetDestination(3); + if (v->state > 0 && v->dest_tile == (uint32)i) v->state = 3; } } } @@ -975,9 +975,9 @@ void ReleaseDisastersTargetingVehicle(VehicleID vehicle) for (DisasterVehicle *v : DisasterVehicle::Iterate()) { /* primary disaster vehicles that have chosen target */ if (v->subtype == ST_SMALL_UFO) { - if (v->current_order.GetDestination() != 0 && v->dest_tile == vehicle) { + if (v->state != 0 && v->dest_tile == vehicle) { /* Revert to target-searching */ - v->current_order.SetDestination(0); + v->state = 0; v->dest_tile = RandomTile(); GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr); v->age = 0; diff --git a/src/disaster_vehicle.h b/src/disaster_vehicle.h index dff97a69e9..0df9913e5d 100644 --- a/src/disaster_vehicle.h +++ b/src/disaster_vehicle.h @@ -38,6 +38,7 @@ struct DisasterVehicle FINAL : public SpecializedVehiclesubtype == 2 /* ST_SMALL_UFO */ && v->current_order.GetDestination() != 0) { + for (DisasterVehicle *v : DisasterVehicle::Iterate()) { + if (v->subtype == 2 /* ST_SMALL_UFO */ && v->state != 0) { const Vehicle *u = Vehicle::GetIfValid(v->dest_tile); if (u == nullptr || u->type != VEH_ROAD || !RoadVehicle::From(u)->IsFrontEngine()) { delete v; diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 723d142a6c..303c05f6e0 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1347,6 +1347,10 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } v->current_order.AssignOrder(UnpackOldOrder(_old_order)); + if (v->type == VEH_DISASTER) { + DisasterVehicle::From(v)->state = UnpackOldOrder(_old_order).GetDestination(); + } + v->next = (Vehicle *)(size_t)_old_next_ptr; if (_cargo_count != 0 && CargoPacket::CanAllocateItem()) { diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 1f07c1bb99..a30033078e 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -352,6 +352,7 @@ enum SaveLoadVersion : uint16 { SLV_EXTEND_VEHICLE_RANDOM, ///< 310 PR#10701 Extend vehicle random bits. SLV_EXTEND_ENTITY_MAPPING, ///< 311 PR#10672 Extend entity mapping range. + SLV_DISASTER_VEH_STATE, ///< 312 PR#10798 Explicit storage of disaster vehicle state. SL_MAX_VERSION, ///< Highest possible saveload version }; diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 13c79438f1..1026fa5482 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -953,8 +953,9 @@ public: SLE_VAR(Vehicle, owner, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), - SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, SLV_5, SL_MAX_VERSION), + SLE_CONDVARNAME(DisasterVehicle, state, "current_order.dest", SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_5), + SLE_CONDVARNAME(DisasterVehicle, state, "current_order.dest", SLE_UINT16, SLV_5, SLV_DISASTER_VEH_STATE), + SLE_CONDVAR(DisasterVehicle, state, SLE_UINT16, SLV_DISASTER_VEH_STATE, SL_MAX_VERSION), SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), From 86e5dfce3da4d2392a43989ff4327d1182536279 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 12 May 2023 20:56:09 +0200 Subject: [PATCH 05/58] Codechange: use std::string instead of strecat to build hotkey strings --- src/hotkeys.cpp | 58 ++++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 0f76aca4de..2e8e56a3f3 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -167,53 +167,41 @@ static void ParseHotkeys(Hotkey *hotkey, const char *value) * by a '+'. * @param keycode The keycode to convert to a string. * @return A string representation of this keycode. - * @note The return value is a static buffer, stredup the result before calling - * this function again. */ -static const char *KeycodeToString(uint16 keycode) +static std::string KeycodeToString(uint16 keycode) { - static char buf[32]; - buf[0] = '\0'; - bool first = true; + std::string str; if (keycode & WKC_GLOBAL_HOTKEY) { - strecat(buf, "GLOBAL", lastof(buf)); - first = false; + str += "GLOBAL"; } if (keycode & WKC_SHIFT) { - if (!first) strecat(buf, "+", lastof(buf)); - strecat(buf, "SHIFT", lastof(buf)); - first = false; + if (!str.empty()) str += "+"; + str += "SHIFT"; } if (keycode & WKC_CTRL) { - if (!first) strecat(buf, "+", lastof(buf)); - strecat(buf, "CTRL", lastof(buf)); - first = false; + if (!str.empty()) str += "+"; + str += "CTRL"; } if (keycode & WKC_ALT) { - if (!first) strecat(buf, "+", lastof(buf)); - strecat(buf, "ALT", lastof(buf)); - first = false; + if (!str.empty()) str += "+"; + str += "ALT"; } if (keycode & WKC_META) { - if (!first) strecat(buf, "+", lastof(buf)); - strecat(buf, "META", lastof(buf)); - first = false; + if (!str.empty()) str += "+"; + str += "META"; } - if (!first) strecat(buf, "+", lastof(buf)); + if (!str.empty()) str += "+"; keycode = keycode & ~WKC_SPECIAL_KEYS; for (uint i = 0; i < lengthof(_keycode_to_name); i++) { if (_keycode_to_name[i].keycode == keycode) { - strecat(buf, _keycode_to_name[i].name, lastof(buf)); - return buf; + str += _keycode_to_name[i].name; + return str; } } assert(keycode < 128); - char key[2]; - key[0] = keycode; - key[1] = '\0'; - strecat(buf, key, lastof(buf)); - return buf; + str.push_back(keycode); + return str; } /** @@ -221,19 +209,15 @@ static const char *KeycodeToString(uint16 keycode) * keycodes are attached to the hotkey they are split by a comma. * @param hotkey The keycodes of this hotkey need to be converted to a string. * @return A string representation of all keycodes. - * @note The return value is a static buffer, stredup the result before calling - * this function again. */ -const char *SaveKeycodes(const Hotkey *hotkey) +std::string SaveKeycodes(const Hotkey *hotkey) { - static char buf[128]; - buf[0] = '\0'; + std::string str; for (uint i = 0; i < hotkey->keycodes.size(); i++) { - const char *str = KeycodeToString(hotkey->keycodes[i]); - if (i > 0) strecat(buf, ",", lastof(buf)); - strecat(buf, str, lastof(buf)); + if (i > 0) str += ","; + str += KeycodeToString(hotkey->keycodes[i]); } - return buf; + return str; } /** From 941dbadf9e0b7ae8fe1f6905b98e48d01463f55a Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 12 May 2023 12:58:31 +0100 Subject: [PATCH 06/58] Codechange: Add and use GetScrolledItemFromWidget to get a list item. This function returns an iterator, either to the selected item or the container's end. This makes handling the result more robust as indices are not used. --- src/autoreplace_gui.cpp | 7 +++---- src/bridge_gui.cpp | 6 +++--- src/build_vehicle_gui.cpp | 7 +++---- src/graph_gui.cpp | 10 +++------- src/group_gui.cpp | 31 +++++++++++++++-------------- src/industry_gui.cpp | 14 ++++++------- src/network/network_content_gui.cpp | 8 ++++---- src/network/network_gui.cpp | 6 +++--- src/newgrf_gui.cpp | 18 ++++++++--------- src/rail_gui.cpp | 6 +++--- src/road_gui.cpp | 6 +++--- src/signs_gui.cpp | 6 +++--- src/station_gui.cpp | 6 +++--- src/town_gui.cpp | 6 +++--- src/vehicle_gui.cpp | 6 +++--- src/widget_type.h | 22 ++++++++++++++++++++ 16 files changed, 91 insertions(+), 74 deletions(-) diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index fede79ef85..cb585ebde7 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -617,12 +617,11 @@ public: } else { click_side = 1; } - uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); - size_t engine_count = this->engines[click_side].size(); EngineID e = INVALID_ENGINE; - if (i < engine_count) { - const auto &item = this->engines[click_side][i]; + const auto it = this->vscroll[click_side]->GetScrolledItemFromWidget(this->engines[click_side], pt.y, this, widget); + if (it != this->engines[click_side].end()) { + const auto &item = *it; const Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL); if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) { /* toggle folded flag on engine */ diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index f2e20c7b21..ae076b352f 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -264,9 +264,9 @@ public: switch (widget) { default: break; case WID_BBS_BRIDGE_LIST: { - uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST); - if (i < this->bridges->size()) { - this->BuildBridge(i); + auto it = this->vscroll->GetScrolledItemFromWidget(*this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST); + if (it != this->bridges->end()) { + this->BuildBridge(it - this->bridges->begin()); this->Close(); } break; diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 685a49472f..209dd17e5b 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1588,11 +1588,10 @@ struct BuildVehicleWindow : Window { break; case WID_BV_LIST: { - uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); - size_t num_items = this->eng_list.size(); EngineID e = INVALID_ENGINE; - if (i < num_items) { - const auto &item = this->eng_list[i]; + const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST); + if (it != this->eng_list.end()) { + const auto &item = *it; const Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL); if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) { /* toggle folded flag on engine */ diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 57d6cc9192..b9284ef949 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -999,13 +999,9 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { } case WID_CPR_MATRIX: { - uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX); - if (row >= this->vscroll->GetCount()) return; - - for (const CargoSpec *cs : _sorted_standard_cargo_specs) { - if (row-- > 0) continue; - - ToggleBit(_legend_excluded_cargo, cs->Index()); + auto it = this->vscroll->GetScrolledItemFromWidget(_sorted_standard_cargo_specs, pt.y, this, WID_CPR_MATRIX); + if (it != _sorted_standard_cargo_specs.end()) { + ToggleBit(_legend_excluded_cargo, (*it)->Index()); this->UpdateExcludedData(); this->SetDirty(); break; diff --git a/src/group_gui.cpp b/src/group_gui.cpp index f6521c34a9..1f5cb04c2f 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -691,10 +691,11 @@ public: break; case WID_GL_LIST_GROUP: { // Matrix Group - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); - if (id_g >= this->groups.size()) return; + auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP); + if (it == this->groups.end()) return; - if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) { + size_t id_g = it - this->groups.begin(); + if ((*it)->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) { /* The group has children, check if the user clicked the fold / unfold button. */ NWidgetCore *group_display = this->GetWidget(widget); int x = _current_text_dir == TD_RTL ? @@ -731,10 +732,10 @@ public: } case WID_GL_LIST_VEHICLE: { // Matrix Vehicle - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehgroups.size()) return; // click out of list bound + auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE); + if (it == this->vehgroups.end()) return; // click out of list bound - const GUIVehicleGroup &vehgroup = this->vehgroups[id_v]; + const GUIVehicleGroup &vehgroup = *it; const Vehicle *v = nullptr; @@ -845,8 +846,8 @@ public: break; case WID_GL_LIST_GROUP: { // Matrix group - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); - GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index; + auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP); + GroupID new_g = it == this->groups.end() ? INVALID_GROUP : (*it)->index; if (this->group_sel != new_g && g->parent != new_g) { Command::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {}); @@ -878,8 +879,8 @@ public: this->group_over = INVALID_GROUP; this->SetDirty(); - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); - GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; + auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP); + GroupID new_g = it == this->groups.end() ? NEW_GROUP : (*it)->index; Command::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, new_g, vindex, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS); break; @@ -891,10 +892,10 @@ public: this->group_over = INVALID_GROUP; this->SetDirty(); - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehgroups.size()) return; // click out of list bound + auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE); + if (it == this->vehgroups.end()) return; // click out of list bound - const GUIVehicleGroup &vehgroup = this->vehgroups[id_v]; + const GUIVehicleGroup &vehgroup = *it; switch (this->grouping) { case GB_NONE: { const Vehicle *v = vehgroup.GetSingleVehicle(); @@ -1023,8 +1024,8 @@ public: break; case WID_GL_LIST_GROUP: { // ... the list of custom groups. - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); - new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; + auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP); + new_group_over = it == this->groups.end() ? NEW_GROUP : (*it)->index; break; } } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 923d09874a..073ea88b14 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -632,9 +632,9 @@ public: } case WID_DPI_MATRIX_WIDGET: { - int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET); - if (y != INT_MAX) { // Is it within the boundaries of available data? - this->selected_type = this->list[y]; + auto it = this->vscroll->GetScrolledItemFromWidget(this->list, pt.y, this, WID_DPI_MATRIX_WIDGET); + if (it != this->list.end()) { // Is it within the boundaries of available data? + this->selected_type = *it; this->UpdateAvailability(); const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); @@ -1742,12 +1742,12 @@ public: break; case WID_ID_INDUSTRY_LIST: { - uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top); - if (p < this->industries.size()) { + auto it = this->vscroll->GetScrolledItemFromWidget(this->industries, pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top); + if (it != this->industries.end()) { if (_ctrl_pressed) { - ShowExtraViewportWindow(this->industries[p]->location.tile); + ShowExtraViewportWindow((*it)->location.tile); } else { - ScrollMainWindowToTile(this->industries[p]->location.tile); + ScrollMainWindowToTile((*it)->location.tile); } } break; diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 18b5470051..33950e43dc 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -799,11 +799,11 @@ public: switch (widget) { case WID_NCL_MATRIX: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX); - if (id_v >= this->content.size()) return; // click out of bounds + auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX); + if (it == this->content.end()) return; // click out of bounds - this->selected = this->content[id_v]; - this->list_pos = id_v; + this->selected = *it; + this->list_pos = it - this->content.begin(); const NWidgetBase *checkbox = this->GetWidget(WID_NCL_CHECKBOX); if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) { diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 72d3d7d94b..3a32d35d05 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -746,9 +746,9 @@ public: break; case WID_NG_MATRIX: { // Show available network games - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX); - this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr; - this->list_pos = (server == nullptr) ? SLP_INVALID : id_v; + auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX); + this->server = (it != this->servers.end()) ? *it : nullptr; + this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin(); this->SetDirty(); /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */ diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index a4323dc98f..1ff5570bbd 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1071,13 +1071,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_AVAIL_LIST: { // Select a non-active GRF. ResetObjectToPlace(); - uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST); + auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST); this->active_sel = nullptr; CloseWindowByClass(WC_GRF_PARAMETERS); - if (i < this->avails.size()) { - if (this->avail_sel != this->avails[i]) CloseWindowByClass(WC_TEXTFILE); - this->avail_sel = this->avails[i]; - this->avail_pos = i; + if (it != this->avails.end()) { + if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE); + this->avail_sel = *it; + this->avail_pos = it - this->avails.begin(); } this->InvalidateData(); if (click_count == 1) { @@ -2123,10 +2123,10 @@ struct SavePresetWindow : public Window { { switch (widget) { case WID_SVP_PRESET_LIST: { - uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SVP_PRESET_LIST); - if (row < this->presets.size()) { - this->selected = row; - this->presetname_editbox.text.Assign(this->presets[row].c_str()); + auto it = this->vscroll->GetScrolledItemFromWidget(this->presets, pt.y, this, WID_SVP_PRESET_LIST); + if (it != this->presets.end()) { + this->selected = it - this->presets.begin(); + this->presetname_editbox.text.Assign(it->c_str()); this->SetWidgetDirty(WID_SVP_PRESET_LIST); this->SetWidgetDirty(WID_SVP_EDITBOX); } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 6e051fde92..970f66129c 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1454,9 +1454,9 @@ public: break; case WID_BRAS_NEWST_LIST: { - int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST); - if (y >= (int)this->station_classes.size()) return; - StationClassID station_class_id = this->station_classes[y]; + auto it = this->vscroll->GetScrolledItemFromWidget(this->station_classes, pt.y, this, WID_BRAS_NEWST_LIST); + if (it == this->station_classes.end()) return; + StationClassID station_class_id = *it; if (_railstation.station_class != station_class_id) { StationClass *station_class = StationClass::Get(station_class_id); _railstation.station_class = station_class_id; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 80f2416bde..3f475c8a8f 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1533,9 +1533,9 @@ public: break; case WID_BROS_NEWST_LIST: { - int y = this->vscrollList->GetScrolledRowFromWidget(pt.y, this, WID_BROS_NEWST_LIST); - if (y >= (int)this->roadstop_classes.size()) return; - RoadStopClassID class_id = this->roadstop_classes[y]; + auto it = this->vscrollList->GetScrolledItemFromWidget(this->roadstop_classes, pt.y, this, WID_BROS_NEWST_LIST); + if (it == this->roadstop_classes.end()) return; + RoadStopClassID class_id = *it; if (_roadstop_gui_settings.roadstop_class != class_id && GetIfClassHasNewStopsByType(RoadStopClass::Get(class_id), roadStopType, _cur_roadtype)) { _roadstop_gui_settings.roadstop_class = class_id; RoadStopClass *rsclass = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class); diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 070ee6261a..c8a61a41fb 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -235,10 +235,10 @@ struct SignListWindow : Window, SignList { { switch (widget) { case WID_SIL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SIL_LIST, WidgetDimensions::scaled.framerect.top); - if (id_v == INT_MAX) return; + auto it = this->vscroll->GetScrolledItemFromWidget(this->signs, pt.y, this, WID_SIL_LIST, WidgetDimensions::scaled.framerect.top); + if (it == this->signs.end()) return; - const Sign *si = this->signs[id_v]; + const Sign *si = *it; ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); break; } diff --git a/src/station_gui.cpp b/src/station_gui.cpp index b8ec485987..f7df5dc657 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -507,10 +507,10 @@ public: { switch (widget) { case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST); - if (id_v >= this->stations.size()) return; // click out of list bound + auto it = this->vscroll->GetScrolledItemFromWidget(this->stations, pt.y, this, WID_STL_LIST); + if (it == this->stations.end()) return; // click out of list bound - const Station *st = this->stations[id_v]; + const Station *st = *it; /* do not check HasStationInUse - it is slow and may be invalid */ assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index c42b92f58c..5b69f8cfa8 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -942,10 +942,10 @@ public: break; case WID_TD_LIST: { // Click on Town Matrix - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top); - if (id_v >= this->towns.size()) return; // click out of town bounds + auto it = this->vscroll->GetScrolledItemFromWidget(this->towns, pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top); + if (it == this->towns.end()) return; // click out of town bounds - const Town *t = this->towns[id_v]; + const Town *t = *it; assert(t != nullptr); if (_ctrl_pressed) { ShowExtraViewportWindow(t->xy); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 9bd28e8e43..77782f070d 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2024,10 +2024,10 @@ public: break; case WID_VL_LIST: { // Matrix to show vehicles - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST); - if (id_v >= this->vehgroups.size()) return; // click out of list bound + auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_VL_LIST); + if (it == this->vehgroups.end()) return; // click out of list bound - const GUIVehicleGroup &vehgroup = this->vehgroups[id_v]; + const GUIVehicleGroup &vehgroup = *it; switch (this->grouping) { case GB_NONE: { const Vehicle *v = vehgroup.GetSingleVehicle(); diff --git a/src/widget_type.h b/src/widget_type.h index e697b3ea5d..e7bbbcd842 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -789,6 +789,28 @@ public: } int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const; + + /** + * Return an iterator pointing to the element of a scrolled widget that a user clicked in. + * @param container Container of elements represented by the scrollbar. + * @param clickpos Vertical position of the mouse click (without taking scrolling into account). + * @param w The window the click was in. + * @param widget Widget number of the widget clicked in. + * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. + * @return Iterator to the element clicked at. If clicked at a wrong position, returns as interator to the end of the container. + */ + template + typename Tcontainer::iterator GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window * const w, int widget, int padding = 0) const + { + assert(this->GetCount() == container.size()); // Scrollbar and container size must match. + int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding); + if (row == INT_MAX) return std::end(container); + + typename Tcontainer::iterator it = std::begin(container); + std::advance(it, row); + return it; + } + EventState UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const; }; From 531d1ae8bc52aae1abbb5e381c343428c1afc856 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 3 May 2023 11:17:52 +0100 Subject: [PATCH 07/58] Codechange: Use GetScrolled(Row/Item)FromWidget in more places. In many instances the clicked row position is 'manually' calculated instead of using the GetScrolledRowFromWidget helper function, with variations on checks. Replace with the two helpers where possible. --- src/airport_gui.cpp | 4 ++-- src/depot_gui.cpp | 6 +++--- src/game/game_gui.cpp | 9 +++++---- src/newgrf_debug_gui.cpp | 9 +++------ src/newgrf_gui.cpp | 8 +++++--- src/object_gui.cpp | 6 +++--- src/order_gui.cpp | 12 ++++-------- src/script/script_gui.cpp | 9 +++++---- src/timetable_gui.cpp | 11 ++++------- 9 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 39fc42deb8..f8015e274a 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -501,8 +501,8 @@ public: break; case WID_AP_AIRPORT_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; - if (num_clicked >= this->vscroll->GetCount()) break; + int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget); + if (num_clicked == INT_MAX) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); break; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index e05682c5a5..7a20022b5b 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -458,10 +458,10 @@ struct DepotWindow : Window { } ym = y % this->resize.step_height; - uint row = y / this->resize.step_height; - if (row >= this->vscroll->GetCapacity()) return MODE_ERROR; + int row = this->vscroll->GetScrolledRowFromWidget(y, this, WID_D_MATRIX); + if (row == INT_MAX) return MODE_ERROR; - uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt; + uint pos = (row * this->num_columns) + xt; if (this->vehicle_list.size() + this->wagon_list.size() <= pos) { /* Clicking on 'line' / 'block' without a vehicle */ diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp index 9f7df2d73a..e4c24e7f25 100644 --- a/src/game/game_gui.cpp +++ b/src/game/game_gui.cpp @@ -267,13 +267,13 @@ struct GSConfigWindow : public Window { break; case WID_GSC_SETTINGS: { - Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); - int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition(); - if (num >= (int)this->visible_settings.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget); + if (it == this->visible_settings.end()) break; - const ScriptConfigItem &config_item = *this->visible_settings[num]; + const ScriptConfigItem &config_item = **it; if (!this->IsEditableItem(config_item)) return; + int num = it - this->visible_settings.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -283,6 +283,7 @@ struct GSConfigWindow : public Window { bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; + Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index 026768f15e..d656837e6b 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -964,12 +964,9 @@ struct SpriteAlignerWindow : Window { break; case WID_SA_LIST: { - const NWidgetBase *nwid = this->GetWidget(widget); - int step_size = nwid->resize_y; - - uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size; - if (i < _newgrf_debug_sprite_picker.sprites.size()) { - SpriteID spr = _newgrf_debug_sprite_picker.sprites[i]; + auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget); + if (it != _newgrf_debug_sprite_picker.sprites.end()) { + SpriteID spr = *it; if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr; } this->SetDirty(); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 1ff5570bbd..b293cef711 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -339,8 +339,10 @@ struct NewGRFParametersWindow : public Window { case WID_NP_BACKGROUND: { if (!this->editable) break; - uint num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND); - if (num >= this->vscroll->GetCount()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->grf_config->param_info, pt.y, this, WID_NP_BACKGROUND); + if (it == this->grf_config->param_info.end()) break; + + uint num = it - this->grf_config->param_info.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -352,7 +354,7 @@ struct NewGRFParametersWindow : public Window { int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; - GRFParameterInfo *par_info = (num < this->grf_config->param_info.size()) ? this->grf_config->param_info[num] : nullptr; + GRFParameterInfo *par_info = *it; if (par_info == nullptr) par_info = GetDummyParameterInfo(num); /* One of the arrows is clicked */ diff --git a/src/object_gui.cpp b/src/object_gui.cpp index a598853e5b..5ccfa8f360 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -517,10 +517,10 @@ public: { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; - if (num_clicked >= (int)this->object_classes.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->object_classes, widget, this, pt.y); + if (it == this->object_classes.end()) break; - this->SelectOtherClass(this->object_classes[num_clicked]); + this->SelectOtherClass(*it); this->SelectFirstAvailableObject(false); break; } diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 4e74ea9694..0721e4d677 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -560,14 +560,10 @@ private: */ VehicleOrderID GetOrderFromPt(int y) { - NWidgetBase *nwid = this->GetWidget(WID_O_ORDER_LIST); - uint sel = (y - nwid->pos_y - WidgetDimensions::scaled.framerect.top) / nwid->resize_y; // Selected line in the WID_O_ORDER_LIST panel. - - if (sel >= this->vscroll->GetCapacity()) return INVALID_VEH_ORDER_ID; - - sel += this->vscroll->GetPosition(); - - return (sel <= vehicle->GetNumOrders()) ? sel : INVALID_VEH_ORDER_ID; + int sel = this->vscroll->GetScrolledRowFromWidget(y, this, WID_O_ORDER_LIST, WidgetDimensions::scaled.framerect.top); + if (sel == INT_MAX) return INVALID_VEH_ORDER_ID; + assert(IsInsideBS(sel, 0, vehicle->GetNumOrders())); + return sel; } /** diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index 61007d23c2..2437d22742 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -425,13 +425,13 @@ struct ScriptSettingsWindow : public Window { { switch (widget) { case WID_SCRS_BACKGROUND: { - Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); - int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition(); - if (num >= (int)this->visible_settings.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget); + if (it == this->visible_settings.end()) break; - const ScriptConfigItem &config_item = *this->visible_settings[num]; + const ScriptConfigItem &config_item = **it; if (!this->IsEditableItem(config_item)) return; + int num = it - this->visible_settings.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -441,6 +441,7 @@ struct ScriptSettingsWindow : public Window { bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; + Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 0d2207aefd..8f52c6580a 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -215,13 +215,10 @@ struct TimetableWindow : Window { int GetOrderFromTimetableWndPt(int y, const Vehicle *v) { - uint sel = (y - this->GetWidget(WID_VT_TIMETABLE_PANEL)->pos_y - WidgetDimensions::scaled.framerect.top) / FONT_HEIGHT_NORMAL; - - if (sel >= this->vscroll->GetCapacity()) return INVALID_ORDER; - - sel += this->vscroll->GetPosition(); - - return (sel < v->GetNumOrders() * 2u) ? sel : INVALID_ORDER; + int sel = this->vscroll->GetScrolledRowFromWidget(y, this, WID_VT_TIMETABLE_PANEL, WidgetDimensions::scaled.framerect.top); + if (sel == INT_MAX) return INVALID_ORDER; + assert(IsInsideBS(sel, 0, v->GetNumOrders() * 2)); + return sel; } /** From d54660184acd659df52702bcc78c564096d62be4 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 13 May 2023 18:23:23 +0200 Subject: [PATCH 08/58] Fix: NewGRF Profile didn't stop if there were no events yet (#10816) This meant you could have the following situation: - You start a profile on a GRF with no events, for N days. - The days pass, the profile should stop. It doesn't. - The profile will never stop, even if the GRF start generating events. - There is no real way to discover this, so .. byebye memory? :) --- src/newgrf_profiling.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/newgrf_profiling.cpp b/src/newgrf_profiling.cpp index e0ea3925e1..18b2cd4dd4 100644 --- a/src/newgrf_profiling.cpp +++ b/src/newgrf_profiling.cpp @@ -98,6 +98,8 @@ uint32 NewGRFProfiler::Finish() if (this->calls.empty()) { IConsolePrint(CC_DEBUG, "Finished profile of NewGRF [{:08X}], no events collected, not writing a file.", BSWAP32(this->grffile->grfid)); + + this->Abort(); return 0; } @@ -116,7 +118,6 @@ uint32 NewGRFProfiler::Finish() } this->Abort(); - return total_microseconds; } From 4a64064c57c60d6ad69ab5b90038f86315ae353a Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 5 May 2023 18:21:08 +0100 Subject: [PATCH 09/58] Codechange: Make NEW_STATION an actual item in join station list. Add NEW_STATION to the nearby station list to indicate that a new station should be built. This removes special-casing for a non-existant list item and keeps the list count and scrollbar count the same. --- src/station_gui.cpp | 50 +++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/station_gui.cpp b/src/station_gui.cpp index f7df5dc657..c53065df64 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2180,6 +2180,7 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) TileArea ctx = ta; _stations_nearby_list.clear(); + _stations_nearby_list.push_back(NEW_STATION); _deleted_stations_nearby.clear(); /* Check the inside, to return, if we sit on another station */ @@ -2268,8 +2269,9 @@ struct SelectStationWindow : Window { /* Determine the widest string */ Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); - for (uint i = 0; i < _stations_nearby_list.size(); i++) { - const T *st = T::Get(_stations_nearby_list[i]); + for (const auto &station : _stations_nearby_list) { + if (station == NEW_STATION) continue; + const T *st = T::Get(station); SetDParam(0, st->index); SetDParam(1, st->facilities); d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); @@ -2287,34 +2289,28 @@ struct SelectStationWindow : Window { if (widget != WID_JS_PANEL) return; Rect tr = r.Shrink(WidgetDimensions::scaled.framerect); - if (this->vscroll->GetPosition() == 0) { - DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); - tr.top += this->resize.step_height; + for (uint i = this->vscroll->GetPosition(); i < _stations_nearby_list.size(); ++i, tr.top += this->resize.step_height) { + if (_stations_nearby_list[i] == NEW_STATION) { + DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); + } else { + const T *st = T::Get(_stations_nearby_list[i]); + SetDParam(0, st->index); + SetDParam(1, st->facilities); + DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); + } } - for (uint i = std::max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.size(); ++i, tr.top += this->resize.step_height) { - /* Don't draw anything if it extends past the end of the window. */ - if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break; - - const T *st = T::Get(_stations_nearby_list[i - 1]); - SetDParam(0, st->index); - SetDParam(1, st->facilities); - DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); - } } void OnClick(Point pt, int widget, int click_count) override { if (widget != WID_JS_PANEL) return; - uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top); - bool distant_join = (st_index > 0); - if (distant_join) st_index--; - - if (distant_join && st_index >= _stations_nearby_list.size()) return; + auto it = this->vscroll->GetScrolledItemFromWidget(_stations_nearby_list, pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top); + if (it == _stations_nearby_list.end()) return; /* Execute stored Command */ - this->select_station_proc(false, distant_join ? _stations_nearby_list[st_index] : NEW_STATION); + this->select_station_proc(false, *it); /* Close Window; this might cause double frees! */ CloseWindowById(WC_SELECT_STATION, 0); @@ -2342,7 +2338,7 @@ struct SelectStationWindow : Window { { if (!gui_scope) return; FindStationsNearby(this->area, true); - this->vscroll->SetCount(_stations_nearby_list.size() + 1); + this->vscroll->SetCount(_stations_nearby_list.size()); this->SetDirty(); } @@ -2354,13 +2350,9 @@ struct SelectStationWindow : Window { } /* Show coverage area of station under cursor */ - uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top); - if (st_index == 0 || st_index > _stations_nearby_list.size()) { - SetViewportCatchmentStation(nullptr, true); - } else { - st_index--; - SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true); - } + auto it = this->vscroll->GetScrolledItemFromWidget(_stations_nearby_list, pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top); + const Station *st = it == _stations_nearby_list.end() || *it == NEW_STATION ? nullptr : Station::Get(*it); + SetViewportCatchmentStation(st, true); } }; @@ -2404,7 +2396,7 @@ static bool StationJoinerNeeded(TileArea ta, const StationPickerCmdProc &proc) * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. * but join the other station immediately. */ const T *st = FindStationsNearby(ta, false); - return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0); + return st == nullptr && (_settings_game.station.adjacent_stations || std::any_of(std::begin(_stations_nearby_list), std::end(_stations_nearby_list), [](StationID s) { return s != NEW_STATION; })); } /** From a92755de81f24a9a6ca6c1f587cd57673b067edb Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 12 May 2023 20:51:54 +0100 Subject: [PATCH 10/58] Codechange: Use iterator erase pattern. --- src/station_gui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/station_gui.cpp b/src/station_gui.cpp index c53065df64..46db6601e4 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -2138,12 +2138,12 @@ static bool AddNearbyStation(TileIndex tile, void *user_data) TileArea *ctx = (TileArea *)user_data; /* First check if there were deleted stations here */ - for (uint i = 0; i < _deleted_stations_nearby.size(); i++) { - auto ts = _deleted_stations_nearby.begin() + i; - if (ts->tile == tile) { - _stations_nearby_list.push_back(_deleted_stations_nearby[i].station); - _deleted_stations_nearby.erase(ts); - i--; + for (auto it = _deleted_stations_nearby.begin(); it != _deleted_stations_nearby.end(); /* nothing */) { + if (it->tile == tile) { + _stations_nearby_list.push_back(it->station); + it = _deleted_stations_nearby.erase(it); + } else { + ++it; } } From e1b653137f3cbd6942d627f7bdaba994370d8b67 Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 13 May 2023 18:41:08 +0000 Subject: [PATCH 11/58] Update: Translations from eints finnish: 4 changes by hpiirai --- src/lang/finnish.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 80f6cce23f..7418d0467b 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -2691,8 +2691,11 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Rakenna STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Valitse asemaluokka STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Valitse asematyyppi -STR_STATION_CLASS_DFLT :Oletusasema +STR_STATION_CLASS_DFLT :Oletus +STR_STATION_CLASS_DFLT_STATION :Oletusasema +STR_STATION_CLASS_DFLT_ROADSTOP :Oletuspysäkki STR_STATION_CLASS_WAYP :Reittipisteet +STR_STATION_CLASS_WAYP_WAYPOINT :Oletusreittipiste # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Opastimien valinta From a372c59483a36d361d9e043dbee2a90ec24fcf69 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 13 May 2023 08:58:24 +0200 Subject: [PATCH 12/58] Codechange: replace C-style (stredup) chat completion with std::string_view --- src/network/network_chat_gui.cpp | 73 +++++++++++++++----------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 20fd7cedf9..cf04ebcef9 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -323,18 +323,16 @@ struct NetworkChatWindow : public Window { * Find the next item of the list of things that can be auto-completed. * @param item The current indexed item to return. This function can, and most * likely will, alter item, to skip empty items in the arrays. - * @return Returns the char that matched to the index. + * @return Returns the view that matched to the index. */ - const char *ChatTabCompletionNextItem(uint *item) + std::optional ChatTabCompletionNextItem(uint *item) { - static char chat_tab_temp_buffer[64]; - /* First, try clients */ if (*item < MAX_CLIENT_SLOTS) { /* Skip inactive clients */ for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) { *item = ci->index; - return ci->client_name.c_str(); + return ci->client_name; } *item = MAX_CLIENT_SLOTS; } @@ -346,12 +344,11 @@ struct NetworkChatWindow : public Window { for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) { /* Get the town-name via the string-system */ SetDParam(0, t->index); - GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer)); - return &chat_tab_temp_buffer[0]; + return GetString(STR_TOWN_NAME); } } - return nullptr; + return std::nullopt; } /** @@ -359,13 +356,14 @@ struct NetworkChatWindow : public Window { * the word right from that as to complete. It also writes a \0 at the * position of the space (if any). If nothing found, buf is returned. */ - static char *ChatTabCompletionFindText(char *buf) + static std::string_view ChatTabCompletionFindText(std::string_view &buf) { - char *p = strrchr(buf, ' '); - if (p == nullptr) return buf; + auto it = buf.find_last_of(' '); + if (it == std::string_view::npos) return buf; - *p = '\0'; - return p + 1; + std::string_view res = buf.substr(it + 1); + buf.remove_suffix(res.size() + 1); + return res; } /** @@ -373,46 +371,44 @@ struct NetworkChatWindow : public Window { */ void ChatTabCompletion() { - static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH]; - assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf)); + static std::string _chat_tab_completion_buf; Textbuf *tb = &this->message_editbox.text; - size_t len, tb_len; - uint item; - char *tb_buf, *pre_buf; - const char *cur_name; + uint item = 0; bool second_scan = false; - item = 0; - - /* Copy the buffer so we can modify it without damaging the real data */ - pre_buf = (_chat_tab_completion_active) ? stredup(_chat_tab_completion_buf) : stredup(tb->buf); + /* Create views, so we do not need to copy the data for now. */ + std::string_view pre_buf = _chat_tab_completion_active ? std::string_view(_chat_tab_completion_buf) : std::string_view(tb->buf); + std::string_view tb_buf = ChatTabCompletionFindText(pre_buf); - tb_buf = ChatTabCompletionFindText(pre_buf); - tb_len = strlen(tb_buf); + /* + * Comparing pointers of the data, as both "Hi:" and "Hi: Hi:" will result in + * tb_buf and pre_buf being "Hi:", which would be equal in content but not in context. + */ + bool begin_of_line = tb_buf.data() == pre_buf.data(); - while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) { + std::optional cur_item; + while ((cur_item = ChatTabCompletionNextItem(&item)).has_value()) { + std::string_view cur_name = cur_item.value(); item++; if (_chat_tab_completion_active) { /* We are pressing TAB again on the same name, is there another name * that starts with this? */ if (!second_scan) { - size_t offset; - size_t length; + std::string_view view; /* If we are completing at the begin of the line, skip the ': ' we added */ - if (tb_buf == pre_buf) { - offset = 0; - length = (tb->bytes - 1) - 2; + if (begin_of_line) { + view = std::string_view(tb->buf, (tb->bytes - 1) - 2); } else { /* Else, find the place we are completing at */ - offset = strlen(pre_buf) + 1; - length = (tb->bytes - 1) - offset; + size_t offset = pre_buf.size() + 1; + view = std::string_view(tb->buf + offset, (tb->bytes - 1) - offset); } /* Compare if we have a match */ - if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true; + if (cur_name == view) second_scan = true; continue; } @@ -420,21 +416,19 @@ struct NetworkChatWindow : public Window { /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ } - len = strlen(cur_name); - if (tb_len < len && StrStartsWith(cur_name, tb_buf)) { + if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) { /* Save the data it was before completion */ - if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf); + if (!second_scan) _chat_tab_completion_buf = tb->buf; _chat_tab_completion_active = true; /* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ - if (pre_buf == tb_buf) { + if (begin_of_line) { this->message_editbox.text.Assign(fmt::format("{}: ", cur_name)); } else { this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name)); } this->SetDirty(); - free(pre_buf); return; } } @@ -446,7 +440,6 @@ struct NetworkChatWindow : public Window { this->SetDirty(); } - free(pre_buf); } Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override From 1fe7bbba8a41dbcbe8dda398f2330cb310f801ca Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 13 May 2023 23:17:11 +0200 Subject: [PATCH 13/58] Codechange: rework NewGRFProfiler to use ticks instead of calendar-days (#10815) We are planning to allow things like freezing the calendar, which makes this variable a bit problemetic. So instead, suggest to the user how many ticks there are in a calendar day, and let them figure out how many ticks they want. Additionally, use a TimeoutTimer for this, instead of an end-date variable which is checked in an IntervalTimer. --- src/console_cmds.cpp | 19 +++++++------------ src/newgrf_profiling.cpp | 28 ++++++++++++++++++++-------- src/newgrf_profiling.h | 3 ++- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index b3dff03c03..19c7ed0c8a 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2203,8 +2203,8 @@ DEF_CONSOLE_CMD(ConNewGRFProfile) IConsolePrint(CC_HELP, " Select one or more GRFs for profiling."); IConsolePrint(CC_HELP, "Usage: 'newgrf_profile unselect ...':"); IConsolePrint(CC_HELP, " Unselect one or more GRFs from profiling. Use the keyword \"all\" instead of a GRF number to unselect all. Removing an active profiler aborts data collection."); - IConsolePrint(CC_HELP, "Usage: 'newgrf_profile start []':"); - IConsolePrint(CC_HELP, " Begin profiling all selected GRFs. If a number of days is provided, profiling stops after that many in-game days."); + IConsolePrint(CC_HELP, "Usage: 'newgrf_profile start []':"); + IConsolePrint(CC_HELP, " Begin profiling all selected GRFs. If a number of ticks is provided, profiling stops after that many game ticks. There are 74 ticks in a calendar day."); IConsolePrint(CC_HELP, "Usage: 'newgrf_profile stop':"); IConsolePrint(CC_HELP, " End profiling and write the collected data to CSV files."); IConsolePrint(CC_HELP, "Usage: 'newgrf_profile abort':"); @@ -2284,16 +2284,11 @@ DEF_CONSOLE_CMD(ConNewGRFProfile) } if (started > 0) { IConsolePrint(CC_DEBUG, "Started profiling for GRFID{} {}.", (started > 1) ? "s" : "", grfids); + if (argc >= 3) { - int days = std::max(atoi(argv[2]), 1); - _newgrf_profile_end_date = TimerGameCalendar::date + days; - - char datestrbuf[32]{ 0 }; - SetDParam(0, _newgrf_profile_end_date); - GetString(datestrbuf, STR_JUST_DATE_ISO, lastof(datestrbuf)); - IConsolePrint(CC_DEBUG, "Profiling will automatically stop on game date {}.", datestrbuf); - } else { - _newgrf_profile_end_date = MAX_DATE; + uint64 ticks = std::max(atoi(argv[2]), 1); + NewGRFProfiler::StartTimer(ticks); + IConsolePrint(CC_DEBUG, "Profiling will automatically stop after {} ticks.", ticks); } } else if (_newgrf_profilers.empty()) { IConsolePrint(CC_ERROR, "No GRFs selected for profiling, did not start."); @@ -2314,7 +2309,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile) for (NewGRFProfiler &pr : _newgrf_profilers) { pr.Abort(); } - _newgrf_profile_end_date = MAX_DATE; + NewGRFProfiler::AbortTimer(); return true; } diff --git a/src/newgrf_profiling.cpp b/src/newgrf_profiling.cpp index 18b2cd4dd4..f3700d453b 100644 --- a/src/newgrf_profiling.cpp +++ b/src/newgrf_profiling.cpp @@ -14,14 +14,12 @@ #include "spritecache.h" #include "walltime_func.h" #include "timer/timer.h" -#include "timer/timer_game_calendar.h" #include "timer/timer_game_tick.h" #include std::vector _newgrf_profilers; -TimerGameCalendar::Date _newgrf_profile_end_date; /** @@ -142,8 +140,10 @@ std::string NewGRFProfiler::GetOutputFilename() const return std::string(filepath); } -uint32 NewGRFProfiler::FinishAll() +/* static */ uint32 NewGRFProfiler::FinishAll() { + NewGRFProfiler::AbortTimer(); + uint64 max_ticks = 0; uint32 total_microseconds = 0; for (NewGRFProfiler &pr : _newgrf_profilers) { @@ -157,17 +157,29 @@ uint32 NewGRFProfiler::FinishAll() IConsolePrint(CC_DEBUG, "Total NewGRF callback processing: {} microseconds over {} ticks.", total_microseconds, max_ticks); } - _newgrf_profile_end_date = MAX_DATE; - return total_microseconds; } /** * Check whether profiling is active and should be finished. */ -static IntervalTimer _check_profiling_finished({TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [](auto) +static TimeoutTimer _profiling_finish_timeout(0, []() { - if (_newgrf_profilers.empty() || _newgrf_profile_end_date > TimerGameCalendar::date) return; - NewGRFProfiler::FinishAll(); }); + +/** + * Start the timeout timer that will finish all profiling sessions. + */ +/* static */ void NewGRFProfiler::StartTimer(uint64 ticks) +{ + _profiling_finish_timeout.Reset(ticks); +} + +/** + * Abort the timeout timer, so the timer callback is never called. + */ +/* static */ void NewGRFProfiler::AbortTimer() +{ + _profiling_finish_timeout.Abort(); +} diff --git a/src/newgrf_profiling.h b/src/newgrf_profiling.h index 34f1d0959e..09b504fe18 100644 --- a/src/newgrf_profiling.h +++ b/src/newgrf_profiling.h @@ -34,6 +34,8 @@ struct NewGRFProfiler { void Abort(); std::string GetOutputFilename() const; + static void StartTimer(uint64 ticks); + static void AbortTimer(); static uint32 FinishAll(); /** Measurement of a single sprite group resolution */ @@ -56,6 +58,5 @@ struct NewGRFProfiler { }; extern std::vector _newgrf_profilers; -extern TimerGameCalendar::Date _newgrf_profile_end_date; #endif /* NEWGRF_PROFILING_H */ From 07473bfd2e4076588bdca73e492974497356151c Mon Sep 17 00:00:00 2001 From: PeterN Date: Sat, 13 May 2023 22:27:32 +0100 Subject: [PATCH 14/58] Fix: Don't use a loop to test if classid is valid. (#10818) Additionally the Object class test was broken. --- src/object_gui.cpp | 15 ++------------- src/rail_gui.cpp | 9 +-------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 5ccfa8f360..97391594d2 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -182,19 +182,8 @@ public: } else { /* Check if the previously selected object class is not available anymore as a * result of starting a new game without the corresponding NewGRF. */ - bool available = false; - for (uint i = 0; ObjectClass::GetClassCount(); ++i) { - if ((ObjectClassID)i == _selected_object_class) { - available = true; - break; - } - } - - if (available) { - this->SelectOtherClass(_selected_object_class); - } else { - this->SelectOtherClass(this->object_classes[0]); - } + bool available = _selected_object_class < ObjectClass::GetClassCount(); + this->SelectOtherClass(available ? _selected_object_class : this->object_classes[0]); } if (this->CanRestoreSelectedObject()) { diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 970f66129c..e3ac337845 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1089,14 +1089,7 @@ public: } else { /* Check if the previously selected station class is not available anymore as a * result of starting a new game without the corresponding NewGRF. */ - bool available = false; - for (uint i = 0; i < StationClass::GetClassCount(); ++i) { - if ((StationClassID)i == _railstation.station_class) { - available = true; - break; - } - } - + bool available = _railstation.station_class < StationClass::GetClassCount(); this->SelectOtherClass(available ? _railstation.station_class : StationClassID::STAT_CLASS_DFLT); } } From 385b25df63d5214f857e212f74372e7a7617beb7 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sat, 13 May 2023 23:18:36 +0100 Subject: [PATCH 15/58] Fix #10819, Fix #10811: GetVehicleFromDepotWndPt used widget- instead of window-relative positions. (#10820) Pass window-relative positions instead, and adjust for relative positions where needed within the function itself. This simplifies calling code. --- src/depot_gui.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 7a20022b5b..49bec452ea 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -445,6 +445,8 @@ struct DepotWindow : Window { DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const { const NWidgetCore *matrix_widget = this->GetWidget(WID_D_MATRIX); + /* Make X relative to widget. Y is left alone for GetScrolledRowFromWidget(). */ + x -= matrix_widget->pos_x; /* In case of RTL the widgets are swapped as a whole */ if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x; @@ -456,7 +458,7 @@ struct DepotWindow : Window { xm = x % this->resize.step_width; if (xt >= this->num_columns) return MODE_ERROR; } - ym = y % this->resize.step_height; + ym = (y - matrix_widget->pos_y) % this->resize.step_height; int row = this->vscroll->GetScrolledRowFromWidget(y, this, WID_D_MATRIX); if (row == INT_MAX) return MODE_ERROR; @@ -762,11 +764,9 @@ struct DepotWindow : Window { void OnClick(Point pt, int widget, int click_count) override { switch (widget) { - case WID_D_MATRIX: { // List - NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); - this->DepotClick(pt.x - nwi->pos_x, pt.y - nwi->pos_y); + case WID_D_MATRIX: // List + this->DepotClick(pt.x, pt.y); break; - } case WID_D_BUILD: // Build vehicle ResetObjectToPlace(); @@ -849,8 +849,7 @@ struct DepotWindow : Window { GetDepotVehiclePtData gdvp = { nullptr, nullptr }; const Vehicle *v = nullptr; - NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); - DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp); + DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp); if (this->type == VEH_TRAIN) v = gdvp.wagon; @@ -1005,11 +1004,10 @@ struct DepotWindow : Window { return; } - NWidgetBase *matrix = this->GetWidget(widget); const Vehicle *v = nullptr; GetDepotVehiclePtData gdvp = {nullptr, nullptr}; - if (this->GetVehicleFromDepotWndPt(pt.x - matrix->pos_x, pt.y - matrix->pos_y, &v, &gdvp) != MODE_DRAG_VEHICLE) return; + if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) != MODE_DRAG_VEHICLE) return; VehicleID new_vehicle_over = INVALID_VEHICLE; if (gdvp.head != nullptr) { @@ -1042,11 +1040,10 @@ struct DepotWindow : Window { this->sel = INVALID_VEHICLE; this->SetDirty(); - NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); if (this->type == VEH_TRAIN) { GetDepotVehiclePtData gdvp = { nullptr, nullptr }; - if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { + if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && _ctrl_pressed) { Command::Post(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true); } else if (gdvp.wagon == nullptr || gdvp.wagon->index != sel) { @@ -1056,7 +1053,7 @@ struct DepotWindow : Window { ShowVehicleViewWindow(gdvp.head); } } - } else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) { + } else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) { ShowVehicleViewWindow(v); } break; From 23ce42ad91a9147d3d58f3ee499a3f09eb837655 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 14 May 2023 08:22:09 +0100 Subject: [PATCH 16/58] Codechange: Use std::move for bridge list. (#10821) This follows the pattern for dropdown lists, and avoids new/delete and pointers. --- src/bridge_gui.cpp | 63 +++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index ae076b352f..e4fbf9c550 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -84,7 +84,7 @@ private: TileIndex end_tile; TransportType transport_type; byte road_rail_type; - GUIBridgeList *bridges; + GUIBridgeList bridges; int bridgetext_offset; ///< Horizontal offset of the text describing the bridge properties in #WID_BBS_BRIDGE_LIST relative to the left edge. Scrollbar *vscroll; @@ -109,21 +109,21 @@ private: void BuildBridge(uint8 i) { switch (this->transport_type) { - case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->at(i).index; break; - case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->at(i).index; break; + case TRANSPORT_RAIL: _last_railbridge_type = this->bridges.at(i).index; break; + case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges.at(i).index; break; default: break; } Command::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, - this->end_tile, this->start_tile, this->transport_type, this->bridges->at(i).index, this->road_rail_type); + this->end_tile, this->start_tile, this->transport_type, this->bridges.at(i).index, this->road_rail_type); } /** Sort the builable bridges */ void SortBridgeList() { - this->bridges->Sort(); + this->bridges.Sort(); /* Display the current sort variant */ - this->GetWidget(WID_BBS_DROPDOWN_CRITERIA)->widget_data = this->sorter_names[this->bridges->SortType()]; + this->GetWidget(WID_BBS_DROPDOWN_CRITERIA)->widget_data = this->sorter_names[this->bridges.SortType()]; /* Set the modified widgets dirty */ this->SetWidgetDirty(WID_BBS_DROPDOWN_CRITERIA); @@ -148,12 +148,12 @@ private: } public: - BuildBridgeWindow(WindowDesc *desc, TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type, GUIBridgeList *bl) : Window(desc), + BuildBridgeWindow(WindowDesc *desc, TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type, GUIBridgeList &&bl) : Window(desc), start_tile(start), end_tile(end), transport_type(transport_type), road_rail_type(road_rail_type), - bridges(bl) + bridges(std::move(bl)) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_BBS_SCROLLBAR); @@ -162,19 +162,17 @@ public: this->FinishInitNested(transport_type); // Initializes 'this->bridgetext_offset'. this->parent = FindWindowById(WC_BUILD_TOOLBAR, transport_type); - this->bridges->SetListing(this->last_sorting); - this->bridges->SetSortFuncs(this->sorter_funcs); - this->bridges->NeedResort(); + this->bridges.SetListing(this->last_sorting); + this->bridges.SetSortFuncs(this->sorter_funcs); + this->bridges.NeedResort(); this->SortBridgeList(); - this->vscroll->SetCount(bl->size()); + this->vscroll->SetCount(this->bridges.size()); } ~BuildBridgeWindow() { - this->last_sorting = this->bridges->GetListing(); - - delete bridges; + this->last_sorting = this->bridges.GetListing(); } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override @@ -200,7 +198,7 @@ public: case WID_BBS_BRIDGE_LIST: { Dimension sprite_dim = {0, 0}; // Biggest bridge sprite dimension Dimension text_dim = {0, 0}; // Biggest text dimension - for (const BuildBridgeData &bridge_data : *this->bridges) { + for (const BuildBridgeData &bridge_data : this->bridges) { sprite_dim = maxdim(sprite_dim, GetSpriteSize(bridge_data.spec->sprite)); text_dim = maxdim(text_dim, GetStringBoundingBox(GetBridgeSelectString(bridge_data))); } @@ -230,13 +228,13 @@ public: { switch (widget) { case WID_BBS_DROPDOWN_ORDER: - this->DrawSortButtonState(widget, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP); + this->DrawSortButtonState(widget, this->bridges.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_BBS_BRIDGE_LIST: { Rect tr = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix); - for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->size(); i++) { - const BuildBridgeData &bridge_data = this->bridges->at(i); + for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges.size(); i++) { + const BuildBridgeData &bridge_data = this->bridges.at(i); const BridgeSpec *b = bridge_data.spec; DrawSprite(b->sprite, b->pal, tr.left, tr.bottom - GetSpriteSize(b->sprite).height); DrawStringMultiLine(tr.Indent(this->bridgetext_offset, false), GetBridgeSelectString(bridge_data)); @@ -250,7 +248,7 @@ public: EventState OnKeyPress(WChar key, uint16 keycode) override { const uint8 i = keycode - '1'; - if (i < 9 && i < this->bridges->size()) { + if (i < 9 && i < this->bridges.size()) { /* Build the requested bridge */ this->BuildBridge(i); this->Close(); @@ -264,29 +262,29 @@ public: switch (widget) { default: break; case WID_BBS_BRIDGE_LIST: { - auto it = this->vscroll->GetScrolledItemFromWidget(*this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST); - if (it != this->bridges->end()) { - this->BuildBridge(it - this->bridges->begin()); + auto it = this->vscroll->GetScrolledItemFromWidget(this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST); + if (it != this->bridges.end()) { + this->BuildBridge(it - this->bridges.begin()); this->Close(); } break; } case WID_BBS_DROPDOWN_ORDER: - this->bridges->ToggleSortOrder(); + this->bridges.ToggleSortOrder(); this->SetDirty(); break; case WID_BBS_DROPDOWN_CRITERIA: - ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), WID_BBS_DROPDOWN_CRITERIA, 0, 0); + ShowDropDownMenu(this, this->sorter_names, this->bridges.SortType(), WID_BBS_DROPDOWN_CRITERIA, 0, 0); break; } } void OnDropdownSelect(int widget, int index) override { - if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges->SortType() != index) { - this->bridges->SetSortType(index); + if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges.SortType() != index) { + this->bridges.SetSortType(index); this->SortBridgeList(); } @@ -390,15 +388,13 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo StringID errmsg = INVALID_STRING_ID; CommandCost ret = Command::Do(CommandFlagsToDCFlags(GetCommandFlags()) | DC_QUERY_COST, end, start, transport_type, 0, road_rail_type); - GUIBridgeList *bl = nullptr; + GUIBridgeList bl; if (ret.Failed()) { errmsg = ret.GetErrorMessage(); } else { /* check which bridges can be built */ const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2); - bl = new GUIBridgeList(); - Money infra_cost = 0; switch (transport_type) { case TRANSPORT_ROAD: { @@ -431,7 +427,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo type_check = CheckBridgeAvailability(brd_type, bridge_len); if (type_check.Succeeded()) { /* bridge is accepted, add to list */ - BuildBridgeData &item = bl->emplace_back(); + BuildBridgeData &item = bl.emplace_back(); item.index = brd_type; item.spec = GetBridgeSpec(brd_type); /* Add to terraforming & bulldozing costs the cost of the @@ -447,10 +443,9 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo } } - if (bl != nullptr && bl->size() != 0) { - new BuildBridgeWindow(&_build_bridge_desc, start, end, transport_type, road_rail_type, bl); + if (!bl.empty()) { + new BuildBridgeWindow(&_build_bridge_desc, start, end, transport_type, road_rail_type, std::move(bl)); } else { - delete bl; ShowErrorMessage(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, errmsg, WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE); } } From 64930c343a9c79b060cc75427cac69b1eba90c33 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 14 May 2023 09:17:44 +0100 Subject: [PATCH 17/58] Codechange: Pass reference instead of pointer to GUI*Lists. (#10822) Pointer-avoidance. --- src/autoreplace_gui.cpp | 4 ++-- src/build_vehicle_gui.cpp | 8 ++++---- src/company_gui.cpp | 6 +++--- src/engine_gui.cpp | 14 +++++++------- src/engine_gui.h | 4 ++-- src/group_gui.cpp | 10 +++++----- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index cb585ebde7..f71347b516 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -195,10 +195,10 @@ class ReplaceVehicleWindow : public Window { this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) if (draw_left) { - EngList_Sort(&list, &EngineNumberSorter); + EngList_Sort(list, &EngineNumberSorter); } else { _engine_sort_direction = this->descending_sort_order; - EngList_Sort(&list, _engine_sort_functions[this->window_number][this->sort_criteria]); + EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]); } this->engines[side].clear(); diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 209dd17e5b..ded2102e78 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1430,14 +1430,14 @@ struct BuildVehicleWindow : Window { /* make engines first, and then wagons, sorted by selected sort_criteria */ _engine_sort_direction = false; - EngList_Sort(&list, TrainEnginesThenWagonsSorter); + EngList_Sort(list, TrainEnginesThenWagonsSorter); /* and then sort engines */ _engine_sort_direction = this->descending_sort_order; - EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); + EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); /* and finally sort wagons */ - EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines); + EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines); } /* Figure out what road vehicle EngineIDs to put in the list */ @@ -1561,7 +1561,7 @@ struct BuildVehicleWindow : Window { } _engine_sort_direction = this->descending_sort_order; - EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]); + EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]); this->eng_list.swap(list); AddChildren(list, INVALID_ENGINE, 0); diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 37de4a8625..23967879fd 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -690,9 +690,9 @@ private: ShowDropDownList(this, std::move(list), sel, widget); } - void AddChildren(GUIGroupList *source, GroupID parent, int indent) + void AddChildren(GUIGroupList &source, GroupID parent, int indent) { - for (const Group *g : *source) { + for (const Group *g : source) { if (g->parent != parent) continue; this->groups.push_back(g); this->indents.push_back(indent); @@ -740,7 +740,7 @@ private: return r < 0; }); - AddChildren(&list, INVALID_GROUP, 0); + AddChildren(list, INVALID_GROUP, 0); } this->groups.shrink_to_fit(); diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp index 6b56ef91f9..3c995d9fa6 100644 --- a/src/engine_gui.cpp +++ b/src/engine_gui.cpp @@ -324,10 +324,10 @@ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID eng * @param el list to be sorted * @param compare function for evaluation of the quicksort */ -void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare) +void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare) { - if (el->size() < 2) return; - std::sort(el->begin(), el->end(), compare); + if (el.size() < 2) return; + std::sort(el.begin(), el.end(), compare); } /** @@ -337,11 +337,11 @@ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare) * @param begin start of sorting * @param num_items count of items to be sorted */ -void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, size_t begin, size_t num_items) +void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items) { if (num_items < 2) return; - assert(begin < el->size()); - assert(begin + num_items <= el->size()); - std::sort(el->begin() + begin, el->begin() + begin + num_items, compare); + assert(begin < el.size()); + assert(begin + num_items <= el.size()); + std::sort(el.begin() + begin, el.begin() + begin + num_items, compare); } diff --git a/src/engine_gui.h b/src/engine_gui.h index 87af6f3562..b33cfaa36b 100644 --- a/src/engine_gui.h +++ b/src/engine_gui.h @@ -31,8 +31,8 @@ struct GUIEngineListItem { typedef GUIList GUIEngineList; typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort. -void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare); -void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, size_t begin, size_t num_items); +void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare); +void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items); StringID GetEngineCategoryName(EngineID engine); StringID GetEngineInfoString(EngineID engine); diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 1f5cb04c2f..fd2e4759ec 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -136,16 +136,16 @@ private: Dimension column_size[VGC_END]; ///< Size of the columns in the group list. - void AddChildren(GUIGroupList *source, GroupID parent, int indent) + void AddChildren(GUIGroupList &source, GroupID parent, int indent) { - for (const Group *g : *source) { + for (const Group *g : source) { if (g->parent != parent) continue; this->groups.push_back(g); this->indents.push_back(indent); if (g->folded) { /* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */ - auto child = std::find_if(source->begin(), source->end(), [g](const Group *child){ return child->parent == g->index; }); - bool has_children = child != source->end(); + auto child = std::find_if(source.begin(), source.end(), [g](const Group *child){ return child->parent == g->index; }); + bool has_children = child != source.end(); Group::Get(g->index)->folded = has_children; } else { AddChildren(source, g->index, indent + 1); @@ -196,7 +196,7 @@ private: return r < 0; }); - AddChildren(&list, INVALID_GROUP, 0); + AddChildren(list, INVALID_GROUP, 0); this->groups.shrink_to_fit(); this->groups.RebuildDone(); From 9eb0cca93a37613e98596deacc6d5a3aa3831e0f Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 14 May 2023 13:04:59 +0100 Subject: [PATCH 18/58] Fix #10823, Fix #10811: Order list has end marker row. (#10825) --- src/order_gui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 0721e4d677..832999c9b2 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -562,7 +562,8 @@ private: { int sel = this->vscroll->GetScrolledRowFromWidget(y, this, WID_O_ORDER_LIST, WidgetDimensions::scaled.framerect.top); if (sel == INT_MAX) return INVALID_VEH_ORDER_ID; - assert(IsInsideBS(sel, 0, vehicle->GetNumOrders())); + /* One past the orders is the 'End of Orders' line. */ + assert(IsInsideBS(sel, 0, vehicle->GetNumOrders() + 1)); return sel; } From 8493719cf4558afabd38dc37e15c25aa0cd45e78 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 14 May 2023 17:32:45 +0200 Subject: [PATCH 19/58] Fix: padding miscalculated for the network-relay and bootstrap-question GUI (#10827) --- src/bootstrap_gui.cpp | 3 ++- src/network/network_gui.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index 2a2b01a302..b8439a89e5 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -102,7 +102,8 @@ public: { if (widget == WID_BEM_MESSAGE) { *size = GetStringBoundingBox(STR_MISSING_GRAPHICS_ERROR); - size->height = GetStringHeight(STR_MISSING_GRAPHICS_ERROR, size->width - WidgetDimensions::scaled.frametext.Horizontal()) + WidgetDimensions::scaled.frametext.Vertical(); + size->width += WidgetDimensions::scaled.frametext.Horizontal(); + size->height += WidgetDimensions::scaled.frametext.Vertical(); } } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 3a32d35d05..2771d0c074 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -2428,7 +2428,8 @@ struct NetworkAskRelayWindow : public Window { { if (widget == WID_NAR_TEXT) { *size = GetStringBoundingBox(STR_NETWORK_ASK_RELAY_TEXT); - size->height = GetStringHeight(STR_NETWORK_ASK_RELAY_TEXT, size->width - WidgetDimensions::scaled.frametext.Horizontal()) + WidgetDimensions::scaled.frametext.Vertical(); + size->width += WidgetDimensions::scaled.frametext.Horizontal(); + size->height += WidgetDimensions::scaled.frametext.Vertical(); } } From a8daf91eea0b3206658c05a4dbfdb68337539aba Mon Sep 17 00:00:00 2001 From: translators Date: Sun, 14 May 2023 18:40:47 +0000 Subject: [PATCH 20/58] Update: Translations from eints vietnamese: 4 changes by KhoiCanDev hungarian: 74 changes by PstasDev turkish: 4 changes by densxd --- src/lang/hungarian.txt | 90 +++++++++++++++++++++++++++++++++-------- src/lang/turkish.txt | 5 ++- src/lang/vietnamese.txt | 5 ++- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 260f4e1a54..6eac5dc0b4 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -258,6 +258,7 @@ STR_UNITS_VELOCITY_IMPERIAL :{DECIMAL}{NBSP} STR_UNITS_VELOCITY_METRIC :{DECIMAL}{NBSP}km/h STR_UNITS_VELOCITY_SI :{DECIMAL}{NBSP}m/s STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL}{NBSP}mező/nap +STR_UNITS_VELOCITY_KNOTS :{DECIMAL}{NBSP}csomó STR_UNITS_POWER_IMPERIAL :{DECIMAL}{NBSP}LE STR_UNITS_POWER_METRIC :{DECIMAL}{NBSP}LE @@ -406,9 +407,9 @@ STR_GOTO_ORDER_VIEW_TOOLTIP :{BLACK}A járm ###length 31 STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Játék szüneteltetése STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Játék gyorsítása -STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Beállítások -STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Játék mentése, játék elhagyása, kilépés -STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Térkép, extra látkép és feliratok listája +STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Alapbeállítások és beállítások +STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Játék mentése vagy játék elhagyása, kilépés +STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Térkép, extra látkép, rakományáramlás és feliratok listája STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Településlista mutatása STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Támogatások megjelenítése STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Állomások listája @@ -416,9 +417,9 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Pénzüg STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Általános adatok STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Napló STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Célok listája -STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Grafikonok +STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Vállalati grafikonok és rakományok szállítási díja STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}A vállalatok helyezése -STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Gazdasági épület építése, meglévők listázása +STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Gazdasági épületek szemügyre vétele vagy egy új gazdasági épület építése STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Vonatok listája. Ctrl+kattintással válszthatsz a csoport- vagy járműlista között STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Közúti járművek listája. Ctrl+kattintással válszthatsz a csoport- vagy járműlista között STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Hajók listája. Ctrl+kattintással válszthatsz a csoport- vagy járműlista között @@ -432,8 +433,8 @@ STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Vízi ú STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Repülőtér építése STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Nyisd meg a tájrendező ablakot a talaj emeléséhez vagy süllyesztéséhez, faültetéshez stb. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Hang/zene beállításai -STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Legutóbbi üzenet/újsághír, üzenetek beállításai -STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Terület-információ, konzol, MI/Játékszkript nyomkövetés, képmentések, az OpenTTD-ről +STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Legutóbbi üzenet/újsághír megmutatása, üzenetelőzmények vagy minden üzenet törlése +STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Terület-információ, konzol, képmentések, az OpenTTD-ről és fejlesztői eszközök STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Eszköztár váltás # Extra tooltips for the scenario editor toolbar @@ -449,7 +450,7 @@ STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Települ STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Gazdasági épület-generálás STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Út építése STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Villamospálya építése -STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Faültetés. Shift lenyomásával megmutatja a becsült építési költséget +STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Faültetés. Ctrl lenyomásával átlós terület jelölhető ki. Shift lenyomásával megmutatja a becsült építési költséget. STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Felirat lerakása STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Objektum építése. Ctrl lenyomásával átlós terület jelölhető ki. Shift lenyomásával megmutatja a becsült építési költséget. @@ -994,8 +995,22 @@ STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}A látk # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Alapbeállítások +STR_GAME_OPTIONS_TAB_GENERAL :Általános +STR_GAME_OPTIONS_TAB_GENERAL_TT :{BLACK}Állítsd be az általános beállításokat +STR_GAME_OPTIONS_TAB_GRAPHICS :Grafika +STR_GAME_OPTIONS_TAB_GRAPHICS_TT :{BLACK}Állítsd be a grafikával kapcsolatos beállításokat +STR_GAME_OPTIONS_TAB_SOUND :Hang effektek +STR_GAME_OPTIONS_TAB_SOUND_TT :{BLACK}Állítsd be a hanggal és zenével kapcsolatos beállításokat +STR_GAME_OPTIONS_VOLUME :Hangerő +STR_GAME_OPTIONS_SFX_VOLUME :Hang effektek +STR_GAME_OPTIONS_MUSIC_VOLUME :Zene +STR_GAME_OPTIONS_VOLUME_0 :0% +STR_GAME_OPTIONS_VOLUME_25 :25% +STR_GAME_OPTIONS_VOLUME_50 :50% +STR_GAME_OPTIONS_VOLUME_75 :75% +STR_GAME_OPTIONS_VOLUME_100 :100% STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Pénznem STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}A használt pénznem kiválasztása @@ -1050,6 +1065,10 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Az autom # Autosave dropdown ###length 5 STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Nincs +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_10_MINUTES :10 percenként +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_30_MINUTES :30 percenként +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_60_MINUTES :60 percenként +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_120_MINUTES :120 percenként STR_GAME_OPTIONS_LANGUAGE :{BLACK}Nyelv STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Válassz nyelvet @@ -1215,6 +1234,7 @@ STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Összes STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Összes összecsukása STR_CONFIG_SETTING_RESET_ALL :{BLACK}Visszaállítja az összes értéket STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(leírás nem elérhető) +STR_CONFIG_SETTING_VALUE :{PUSH_COLOUR}{ORANGE}{STRING}{POP_COLOUR} STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Alapértelmezett érték: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Beállítás típusa: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Kliens beállítás (mentésben nem tárolva; minden játékot befolyásol) @@ -1270,7 +1290,9 @@ STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Jobbra STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maximális kezdeti hitelkeret: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maximálisan kölcsönözhető összeg (az inflációtól eltekintve) +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_VALUE :{CURRENCY_LONG} ###setting-zero-is-special +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_DISABLED :Nincs kölcsön {RED}Kezdőtőkéhez játékszkript szükséges STR_CONFIG_SETTING_INTEREST_RATE :Kamatláb: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Banki hitel kamat; inflációt is szabályozza, ha be van kapcsolva @@ -1978,15 +2000,17 @@ STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :nincs STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Kezdeti városméret-szorzó: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Átlagos városméret a normál településekhez képest a játék kezdetén +STR_CONFIG_SETTING_LINKGRAPH_RECALC_INTERVAL :Kapcsolatgrafikon frissítése minden {STRING}{NBSP}másodpercben{P 0:2 "" s} +STR_CONFIG_SETTING_LINKGRAPH_RECALC_INTERVAL_HELPTEXT :A kapcsolatgrafikon következő újrakalkulálása között eltelt idő. Minden újrakalkulálás során egy komponens tervei kerülnek kiszámításra. Ez azt jelenti, hogy az X érték beállítása nem jelenti azt, hogy az egész grafikon X másodpercenként frissül. Csak néhány komponens lesz frissítve. Minél rövidebbre van állítva, annál több CPU időre van szükség a kiszámításhoz. Ha hosszabbra van állítva, akkor hosszabb időbe telik, amíg az áruelosztás elkezdődik az új útvonalakon. STR_CONFIG_SETTING_DISTRIBUTION_PAX :Utasok szétosztása: {STRING} -STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :A "szimmetrikus" azt jelenti, hogy megközelítóleg ugyanannyi utas megy majd A-ból B-be, mint B-ből A-ba. Az "aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű utas mehet. "Kézi" esetben az utasok nem lesznek automatikusan szétosztva. +STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :A "Szimmetrikus" azt jelenti, hogy megközelítóleg ugyanannyi utas megy majd A-ból B-be, mint B-ből A-ba. Az "Aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű utas mehet. "Kézi" esetben az utasok nem lesznek automatikusan szétosztva. STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Levelek szétosztása: {STRING} -STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :A "szimmetrikus" azt jelenti, hogy megközelítóleg ugyanannyi levél megy majd A-ból B-be, mint B-ből A-ba. Az "aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű levél mehet. "Kézi" esetben a levelek nem lesznek automatikusan szétosztva. +STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :A "Szimmetrikus" azt jelenti, hogy megközelítóleg ugyanannyi levél megy majd A-ból B-be, mint B-ből A-ba. Az "Aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű levél mehet. "Kézi" esetben a levelek nem lesznek automatikusan szétosztva. STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :A PÁNCÉLOZOTT rakománytípus szétosztása: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :A PÁNCÉLOZOTT rakománytípus a mérsékelt égövi tájon az értéktárgyakat, szubtrópusi tájon a gyémántot, szubarktikus tájon pedig az aranyat jelenti, ezeken a NewGRF-ek változtathatnak. A "szimmetrikus" azt jelenti, hogy megközelítóleg ugyanannyi rakomány megy majd A-ból B-be, mint B-ből A-ba. Az "aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű rakomány mehet. "Kézi" esetben a rakományok nem lesznek automatikusan szétosztva. Szubarktikus esetben az "aszimmetrikus" vagy "kézi" beállítás javasolt, mivel a bankok nem fognak aranyat, ill. gyémántot visszaküldeni a bányáknak. Mérsékelt és szubtropikus égövi esetben a "szimmetrikus" is jó választás, ebben az esetben a bankok a fogadott mennyiségnek megfelelően fognak értéktárgyakat visszaküldeni a küldő banknak. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Egyéb rakománytípusok szétosztása: {STRING} -STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :Az "aszimmetrikus" beállítás esetén a különbözö irányokba tetszőleges mennyiségű rakomány mehet. "Kézi" esetben a rakományok nem lesznek automatikusan szétosztva. +STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :Az "Aszimmetrikus" beállítás esetén a különböző irányokba tetszőleges mennyiségű rakomány mehet. "Kézi" esetben a rakományok nem lesznek automatikusan szétosztva. ###length 3 STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :kézi STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :aszimmetrikus @@ -2003,13 +2027,15 @@ STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :100%-nál kiseb STR_CONFIG_SETTING_SHORT_PATH_SATURATION :A rövidebb utak telítettsége a szabad utak felhasználása előtt: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Gyakran több útvonal is van két adott állomás között. A Cargodist először a legrövidebb útvonalat telíti be, majd a második legrövidebb útvonalat, miután az első útvonal már telített, és így tovább. A telítettséget a kapacitás becslése és a tervezett kihasználtság határozza meg. Amennyiben az összes útvonal telített, és még mindig van igény, az összes útvonalat terhelni fogja, elsősorban a legnagyobb kapacitásúakat. Viszont a legtöbb esetben az algoritmus nem fogja pontosan megbecsülni a kapacitást. Ezen opció segítségével beállíthatjuk, hogy milyen telítettségi szintig legyen kihasználva a rövidebb útvonal a hosszabb útvonal használatba vétele előtt. Állítsd 100%-nál kisebbre, hogy elkerüld a túlterhelődő állomásokat abban az esetben, ha a kapacitás túl lenne becsülve! -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Sebesség mértékegysége: {STRING} +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Sebesség mértékegysége (szárazföldi): {STRING} +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_NAUTICAL :Sebesség mértékegységei (tengeri): {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :A sebességértékek a kiválasztott mértékegységben fognak megjelenni a felhasználói felületen ###length 5 STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Angolszász (mi/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metrikus (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :Játékbeli egység (mező/nap) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_KNOTS :Csomó STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Teljesítmény mértékegysége: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :A teljesítményértékek a kiválasztott mértékegységben fognak megjelenni a felhasználói felületen @@ -2410,6 +2436,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Új vállalat) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Hozz létre egy új vállalatot és csatlakozz STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Ez vagy te STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Ez a játék elindítója +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} kliens / {NUM}/{NUM} vállalat +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}A jelenleg csatlakozott kliensek száma, vállalatok számra és a maximálisan létrehozható vállalatok száma a szerver adminisztrátora által engedélyezve lettek # Matches ConnectionType ###length 5 @@ -2725,8 +2753,11 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Állomá STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Válassz egy megjelenítendő állomásfajtát STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Megépítendő állomástípus kiválasztása -STR_STATION_CLASS_DFLT :Alapértelmezett állomás +STR_STATION_CLASS_DFLT :Alapértelmezett +STR_STATION_CLASS_DFLT_STATION :Alapértelmezett állomás +STR_STATION_CLASS_DFLT_ROADSTOP :Alapértelmezett úttorlasz STR_STATION_CLASS_WAYP :Ellenőrző pontok +STR_STATION_CLASS_WAYP_WAYPOINT :Alapértelmezett vasúti ellenőrző pont # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Jelzőválasztó @@ -2752,6 +2783,10 @@ STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Automata STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Válassz egy vasúti hidat STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Közúti híd építése STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Híd kiválasztása - kattints arra a hídra, amit meg akarsz építeni +STR_SELECT_BRIDGE_INFO_NAME :{GOLD}{STRING} +STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED :{GOLD}{STRING},{} {VELOCITY} +STR_SELECT_BRIDGE_INFO_NAME_COST :{GOLD}{0:STRING},{} {WHITE}{2:CURRENCY_LONG} +STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED_COST :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_BRIDGE_NAME_SUSPENSION_STEEL :Függő, acél STR_BRIDGE_NAME_GIRDER_STEEL :Gerendás, acél STR_BRIDGE_NAME_CANTILEVER_STEEL :Rácsos, acél @@ -2871,7 +2906,7 @@ STR_OBJECT_CLASS_TRNS :Adótornyok STR_PLANT_TREE_CAPTION :{WHITE}Fák STR_PLANT_TREE_TOOLTIP :{BLACK}Ültetendő fa kiválasztása. Ha már van fa a mezőn, akkor újabb fák ültetése a kiválasztott fatípustól függetlenül STR_TREES_RANDOM_TYPE :{BLACK}Véletlenszerű fafélék -STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Véletlenszerűen kiválasztott fákat helyez el. Shift lenyomásával megmutatja a várható telepítési költséget +STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Véletlenszerűen kiválasztott fákat helyez el. Ctrl lenyomásával átlós terület jelölhető ki. Shift lenyomásával megmutatja a becsült építési költséget. STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Véletlenszerű fák STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Véletlenszerűen fákat ültet a térképre STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normál @@ -3399,6 +3434,8 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED}Figyelmeztetés: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Hiba: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Végzetes hiba: {SILVER}{STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A "{STRING}" nevű NewGRF végzetes hibába torkollott:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}A "{STRING}" nevű NewGRF hibába torkollott:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} nem fog működni az OpenTTD által jelentett TTDPatch verzióval STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} a TTD {2:STRING} verziójához van STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} úgy lett tervezve, hogy együtt lesz használva ezzel: {2:STRING} @@ -3856,6 +3893,8 @@ STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}A listá STR_VEHICLE_LIST_REPLACE_VEHICLES :Járművek lecserélése STR_VEHICLE_LIST_SEND_FOR_SERVICING :Javításra küld STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Idei nyereség: {CURRENCY_LONG} (Tavalyi: {CURRENCY_LONG}) +STR_VEHICLE_LIST_CARGO :[{CARGO_LIST}] +STR_VEHICLE_LIST_NAME_AND_CARGO :{STRING} {STRING} STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Elküldi járműtelepre STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Elküldi garázsba @@ -4566,7 +4605,7 @@ STR_TIMETABLE_CLEAR_SPEED :{BLACK}Sebessé STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Sebességkorlátozás törlése a kijelölt utasításból. Ctrl+kattintással kitörlöd a sebességet az összes utasításból. STR_TIMETABLE_RESET_LATENESS :{BLACK}Késés nullázása -STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Késés-számláló nullázása, azaz a jármű pontos lesz +STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Késés-számláló nullázása, azaz a jármű pontos lesz. Ctrl+kattintással az egész csoportot nullázhatod, vagyis a legutolsó pont időben lesz a többi pedig korán STR_TIMETABLE_AUTOFILL :{BLACK}Automatikus kitöltés STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Menetrend automatikus kitöltése a következő út értékeivel Ctrl+kattintással megtartja a várakozási időket @@ -4620,7 +4659,9 @@ STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}A követ STR_AI_CONFIG_HUMAN_PLAYER :Játékos STR_AI_CONFIG_RANDOM_AI :Véletlenszerűen választott MI STR_AI_CONFIG_NONE :(nincs) +STR_AI_CONFIG_NAME_VERSION :{STRING} {YELLOW}v{NUM} STR_AI_CONFIG_MAX_COMPETITORS :{LTBLUE}Ellenfelek száma legfeljebb: {ORANGE}{COMMA} +STR_AI_CONFIG_COMPETITORS_INTERVAL :{LTBLUE}Ellenfelek indítása közötti időtartam: {ORANGE}{COMMA} perc{P "" s} STR_AI_CONFIG_MOVE_UP :{BLACK}Mozgatás Fel STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Kiválasztott MI mozgatása felfelé a listában @@ -4633,7 +4674,7 @@ STR_AI_CONFIG_AI :{SILVER}MI-k STR_AI_CONFIG_CHANGE_AI :{BLACK}MI kiválasztása STR_AI_CONFIG_CHANGE_GAMESCRIPT :{BLACK}Játékszkript kiválasztása -STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Másik szkript betöltése +STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Másik szkript betöltése. Ctrl+kattintás megmutat minden elérhető verziót STR_AI_CONFIG_CONFIGURE :{BLACK}Beállítások STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}A szkript paramétereinek beállítása @@ -4661,7 +4702,9 @@ STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}Magassá STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Minitérkép mentése # Script Parameters +STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Paraméterek STR_AI_SETTINGS_CAPTION_AI :{WHITE}MI paraméterei +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Játékszkript STR_AI_SETTINGS_CLOSE :{BLACK}Bezárás STR_AI_SETTINGS_RESET :{BLACK}Visszaállítás STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -5116,11 +5159,24 @@ STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... túl STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... a repülőgépnek kicsi a hatótávolsága # Extra messages which go on the third line of errors, explaining why orders failed +STR_ERROR_NO_RAIL_STATION :{WHITE}Nem található vasútállomás +STR_ERROR_NO_BUS_STATION :{WHITE}Nem található buszmegálló +STR_ERROR_NO_TRUCK_STATION :{WHITE}Nem található teherautó-rakodóhely +STR_ERROR_NO_DOCK :{WHITE}Kikötő nem található +STR_ERROR_NO_AIRPORT :{WHITE}Nem található repülőtér/Helikopter-leszálló +STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}Nem található megálló kompatibilis úttípussal +STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE :{WHITE}Nem található megálló kompatibilis villamos-típussal +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}Nincsenek csuklós járművek számára kialakított megállóhelyek.{}Csuklós járművek számára áthaladó megállók szükségesek +STR_ERROR_AIRPORT_NO_PLANES :{WHITE}Ez a gép nem tud leszállni ezen a helikopter-leszállón +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}Ez a helikopter nem tud leszállni ezen a repülőtéren +STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}Nem található vasúti ellenőrző pont +STR_ERROR_NO_BUOY :{WHITE}Nem található bója # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}A jármű nem időzíthető STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}A járművek csak az állomáson várakozhatnak STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Ez a jármű nem áll meg ezen az állomáson +STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... menetrend befejezetlen # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... túl sok a felirat @@ -5641,11 +5697,13 @@ STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} +STR_JUST_RIGHT_ARROW :{RIGHT_ARROW} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} +STR_JUST_DECIMAL :{DECIMAL} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index 598df6d867..a35b93df61 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -2692,8 +2692,11 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Sürükl STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Görüntülenecek istasyon türünü seçin STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Yapılacak istasyon türünü seçin -STR_STATION_CLASS_DFLT :Varsayılan istasyon +STR_STATION_CLASS_DFLT :Varsayılan +STR_STATION_CLASS_DFLT_STATION :Varsayılan istasyon +STR_STATION_CLASS_DFLT_ROADSTOP :Varsayılan yol durağı STR_STATION_CLASS_WAYP :Yerimleri +STR_STATION_CLASS_WAYP_WAYPOINT :Varsayılan yol noktası # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Sinyal Seçimi diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 3118280a13..9b970910cd 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -2691,8 +2691,11 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Xây d STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Chọn loại ga để hiển thị STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Chọn loại ga để xây dựng -STR_STATION_CLASS_DFLT :Ga mặc định +STR_STATION_CLASS_DFLT :Mặc định +STR_STATION_CLASS_DFLT_STATION :Trạm mặc định +STR_STATION_CLASS_DFLT_ROADSTOP :Điểm dừng trên đường mặc định STR_STATION_CLASS_WAYP :Điểm mốc +STR_STATION_CLASS_WAYP_WAYPOINT :Điểm mốc mặc định # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Chọn Đèn Tín Hiệu From 4894da67dae6d9fbe5c5e6516807ec44524dc7c1 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 14 May 2023 20:12:26 +0100 Subject: [PATCH 21/58] Codechange: Pass bridge type instead of display row to BuildBridge. (#10828) --- src/bridge_gui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index e4fbf9c550..e2a251f8f2 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -106,15 +106,15 @@ private: return a.spec->speed < b.spec->speed; } - void BuildBridge(uint8 i) + void BuildBridge(BridgeType type) { switch (this->transport_type) { - case TRANSPORT_RAIL: _last_railbridge_type = this->bridges.at(i).index; break; - case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges.at(i).index; break; + case TRANSPORT_RAIL: _last_railbridge_type = type; break; + case TRANSPORT_ROAD: _last_roadbridge_type = type; break; default: break; } Command::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, - this->end_tile, this->start_tile, this->transport_type, this->bridges.at(i).index, this->road_rail_type); + this->end_tile, this->start_tile, this->transport_type, type, this->road_rail_type); } /** Sort the builable bridges */ @@ -250,7 +250,7 @@ public: const uint8 i = keycode - '1'; if (i < 9 && i < this->bridges.size()) { /* Build the requested bridge */ - this->BuildBridge(i); + this->BuildBridge(this->bridges[i].index); this->Close(); return ES_HANDLED; } @@ -264,7 +264,7 @@ public: case WID_BBS_BRIDGE_LIST: { auto it = this->vscroll->GetScrolledItemFromWidget(this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST); if (it != this->bridges.end()) { - this->BuildBridge(it - this->bridges.begin()); + this->BuildBridge(it->index); this->Close(); } break; From 4a6fdc829331dddd4045d9ad91db972ad4083095 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sun, 14 May 2023 21:13:24 +0200 Subject: [PATCH 22/58] Fix: multiplication result converted to larger type Technically unlikely to happen, though uint16 * uint16 get promoted to int and then stored as uint64; similarly uint * uint16 remains uint and gets stored as uint64. In both cases the value can get truncated before the change to uint64. --- src/cargopacket.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 28523e2844..a72e8fe622 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -180,7 +180,7 @@ void CargoList::RemoveFromCache(const CargoPacket *cp, uint count) { assert(count <= cp->count); this->count -= count; - this->cargo_days_in_transit -= cp->days_in_transit * count; + this->cargo_days_in_transit -= static_cast(cp->days_in_transit) * count; } /** @@ -192,7 +192,7 @@ template void CargoList::AddToCache(const CargoPacket *cp) { this->count += cp->count; - this->cargo_days_in_transit += cp->days_in_transit * cp->count; + this->cargo_days_in_transit += static_cast(cp->days_in_transit) * cp->count; } /** Invalidates the cached data and rebuilds it. */ From 3d8d99ba11ae8f5290d58242887fb510efa0fb63 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Thu, 4 May 2023 22:57:11 +0200 Subject: [PATCH 23/58] Add: method to call script functions with std::string --- src/script/squirrel.cpp | 9 +++++++++ src/script/squirrel.hpp | 1 + 2 files changed, 10 insertions(+) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 0ab56049f1..b51e051e8c 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -442,6 +442,15 @@ bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_nam return true; } +bool Squirrel::CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend) +{ + HSQOBJECT ret; + if (!this->CallMethod(instance, method_name, &ret, suspend)) return false; + if (ret._type != OT_STRING) return false; + *res = StrMakeValid(ObjectToString(&ret)); + return true; +} + bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend) { HSQOBJECT ret; diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 444e8a3a0d..77cff710b6 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -160,6 +160,7 @@ public: bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend); bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); } bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend); + bool CallStringMethod(HSQOBJECT instance, const char *method_name, const std::string *res, int suspend); bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend); bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend); From 9b0123ab669cb02a9f614596ec11e01cde1ba3ac Mon Sep 17 00:00:00 2001 From: Rubidium Date: Thu, 4 May 2023 23:06:21 +0200 Subject: [PATCH 24/58] Codechange: use std::string for script API versions --- src/ai/ai_info.cpp | 20 +++++--------------- src/ai/ai_info.hpp | 5 ++--- src/game/game_info.cpp | 12 +++--------- src/game/game_info.hpp | 5 ++--- src/script/script_instance.cpp | 6 ++---- src/script/script_instance.hpp | 4 ++-- src/script/squirrel.hpp | 2 +- 7 files changed, 17 insertions(+), 37 deletions(-) diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index 7e35d89bb7..29dfdf81f4 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -23,7 +23,7 @@ * Check if the API version provided by the AI is supported. * @param api_version The API version as provided by the AI. */ -static bool CheckAPIVersion(const char *api_version) +static bool CheckAPIVersion(const std::string &api_version) { static const std::set versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" }; return versions.find(api_version) != versions.end(); @@ -82,13 +82,13 @@ template <> const char *GetClassName() { return "AIInfo" } /* Try to get the API version the AI is written for. */ if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) { - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; } } else { - info->api_version = stredup("0.7"); + info->api_version = "0.7"; } /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ @@ -104,15 +104,11 @@ template <> const char *GetClassName() { return "AIInfo" SQUserPointer instance; sq_getinstanceup(vm, 2, &instance, nullptr); AIInfo *info = (AIInfo *)instance; - info->api_version = nullptr; + info->api_version = fmt::format("{}.{}", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4)); SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; - char buf[8]; - seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4)); - info->api_version = stredup(buf); - /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ sq_setinstanceup(vm, 2, nullptr); /* Register the AI to the base system */ @@ -122,14 +118,8 @@ template <> const char *GetClassName() { return "AIInfo" AIInfo::AIInfo() : min_loadable_version(0), - use_as_random(false), - api_version(nullptr) -{ -} - -AIInfo::~AIInfo() + use_as_random(false) { - free(this->api_version); } bool AIInfo::CanLoadFromVersion(int version) const diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp index 8f236e09ab..a87b6cc36c 100644 --- a/src/ai/ai_info.hpp +++ b/src/ai/ai_info.hpp @@ -16,7 +16,6 @@ class AIInfo : public ScriptInfo { public: AIInfo(); - ~AIInfo(); /** * Register the functions of this class. @@ -46,12 +45,12 @@ public: /** * Get the API version this AI is written for. */ - const char *GetAPIVersion() const { return this->api_version; } + const std::string &GetAPIVersion() const { return this->api_version; } private: int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this. bool use_as_random; ///< Should this AI be used when the user wants a "random AI"? - const char *api_version; ///< API version used by this AI. + std::string api_version; ///< API version used by this AI. }; /** All static information from an AI library like name, version, etc. */ diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp index b151586c10..2144ebd377 100644 --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -21,7 +21,7 @@ * Check if the API version provided by the Game is supported. * @param api_version The API version as provided by the Game. */ -static bool CheckAPIVersion(const char *api_version) +static bool CheckAPIVersion(const std::string &api_version) { static const std::set versions = { "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" }; return versions.find(api_version) != versions.end(); @@ -73,7 +73,7 @@ template <> const char *GetClassName() { return "GSInf } /* Try to get the API version the AI is written for. */ if (!info->CheckMethod("GetAPIVersion")) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; @@ -88,16 +88,10 @@ template <> const char *GetClassName() { return "GSInf GameInfo::GameInfo() : min_loadable_version(0), - is_developer_only(false), - api_version(nullptr) + is_developer_only(false) { } -GameInfo::~GameInfo() -{ - free(this->api_version); -} - bool GameInfo::CanLoadFromVersion(int version) const { if (version == -1) return true; diff --git a/src/game/game_info.hpp b/src/game/game_info.hpp index cfa900767c..76dbfd546f 100644 --- a/src/game/game_info.hpp +++ b/src/game/game_info.hpp @@ -16,7 +16,6 @@ class GameInfo : public ScriptInfo { public: GameInfo(); - ~GameInfo(); /** * Register the functions of this class. @@ -36,14 +35,14 @@ public: /** * Get the API version this Game is written for. */ - const char *GetAPIVersion() const { return this->api_version; } + const std::string &GetAPIVersion() const { return this->api_version; } bool IsDeveloperOnly() const override { return this->is_developer_only; } private: int min_loadable_version; ///< The Game can load savegame data if the version is equal or greater than this. bool is_developer_only; ///< Is the script selectable by non-developers? - const char *api_version; ///< API version used by this Game. + std::string api_version; ///< API version used by this Game. }; /** All static information from an Game library like name, version, etc. */ diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index 1383a4540b..c0a4f200d9 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -51,7 +51,6 @@ static void PrintFunc(bool error_msg, const std::string &message) ScriptInstance::ScriptInstance(const char *APIName) : engine(nullptr), - versionAPI(nullptr), controller(nullptr), storage(nullptr), instance(nullptr), @@ -113,10 +112,9 @@ void ScriptInstance::RegisterAPI() squirrel_register_std(this->engine); } -bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir) +bool ScriptInstance::LoadCompatibilityScripts(const std::string &api_version, Subdirectory dir) { - char script_name[32]; - seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version); + std::string script_name = fmt::format("compat_{}.nut", api_version); for (Searchpath sp : _valid_searchpaths) { std::string buf = FioGetDirectory(sp, dir); buf += script_name; diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index dae1f6940d..4e98b8df7e 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -248,7 +248,7 @@ public: protected: class Squirrel *engine; ///< A wrapper around the squirrel vm. - const char *versionAPI; ///< Current API used by this script. + std::string versionAPI; ///< Current API used by this script. /** * Register all API functions to the VM. @@ -261,7 +261,7 @@ protected: * @param dir Subdirectory to find the scripts in * @return true iff script loading should proceed */ - bool LoadCompatibilityScripts(const char *api_version, Subdirectory dir); + bool LoadCompatibilityScripts(const std::string &api_version, Subdirectory dir); /** * Tell the script it died. diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 77cff710b6..d290c3ec1a 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -160,7 +160,7 @@ public: bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend); bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); } bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend); - bool CallStringMethod(HSQOBJECT instance, const char *method_name, const std::string *res, int suspend); + bool CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend); bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend); bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend); From a30f7c83bd55feaaf020de66b1d269b80cc5410a Mon Sep 17 00:00:00 2001 From: Rubidium Date: Thu, 4 May 2023 23:16:09 +0200 Subject: [PATCH 25/58] Codechange: use std::string for script names to load --- src/script/script_instance.cpp | 2 +- src/script/script_scanner.cpp | 2 +- src/script/squirrel.cpp | 8 ++++---- src/script/squirrel.hpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index c0a4f200d9..c04d3c2fec 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -120,7 +120,7 @@ bool ScriptInstance::LoadCompatibilityScripts(const std::string &api_version, Su buf += script_name; if (!FileExists(buf)) continue; - if (this->engine->LoadScript(buf.c_str())) return true; + if (this->engine->LoadScript(buf)) return true; ScriptLog::Error("Failed to load API compatibility script"); Debug(script, 0, "Error compiling / running API compatibility script: {}", buf); diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index 8dd88d3ff6..4035dd649a 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -36,7 +36,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length, this->ResetEngine(); try { - this->engine->LoadScript(filename.c_str()); + this->engine->LoadScript(filename); } catch (Script_FatalError &e) { Debug(script, 0, "Fatal error '{}' when trying to load the script '{}'.", e.GetErrorMessage(), filename); return false; diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index b51e051e8c..3c8a802cc8 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -634,7 +634,7 @@ static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger return ret; } -SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror) +SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool printerror) { ScriptAllocatorScope alloc_scope(this); @@ -712,7 +712,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer } SQFile f(file, size); - if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) { + if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename.c_str(), printerror))) { FioFCloseFile(file); return SQ_OK; } @@ -720,7 +720,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer return SQ_ERROR; } -bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root) +bool Squirrel::LoadScript(HSQUIRRELVM vm, const std::string &script, bool in_root) { ScriptAllocatorScope alloc_scope(this); @@ -744,7 +744,7 @@ bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root) return false; } -bool Squirrel::LoadScript(const char *script) +bool Squirrel::LoadScript(const std::string &script) { return LoadScript(this->vm, script); } diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index d290c3ec1a..f9471ff14b 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -84,13 +84,13 @@ public: * @param script The full script-name to load. * @return False if loading failed. */ - bool LoadScript(const char *script); - bool LoadScript(HSQUIRRELVM vm, const char *script, bool in_root = true); + bool LoadScript(const std::string &script); + bool LoadScript(HSQUIRRELVM vm, const std::string &script, bool in_root = true); /** * Load a file to a given VM. */ - SQRESULT LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror); + SQRESULT LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool printerror); /** * Adds a function to the stack. Depending on the current state this means From 0fd9eb0faaf279ed7eea28d2d45b38af8fd6040f Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 5 May 2023 09:53:34 +0200 Subject: [PATCH 26/58] Codechange: use std::string for script info/library finding --- src/ai/ai.hpp | 4 ++-- src/ai/ai_config.cpp | 2 +- src/ai/ai_config.hpp | 2 +- src/ai/ai_core.cpp | 4 ++-- src/ai/ai_instance.cpp | 2 +- src/ai/ai_instance.hpp | 2 +- src/ai/ai_scanner.cpp | 6 +++--- src/ai/ai_scanner.hpp | 4 ++-- src/game/game.hpp | 4 ++-- src/game/game_config.cpp | 2 +- src/game/game_config.hpp | 2 +- src/game/game_core.cpp | 4 ++-- src/game/game_instance.cpp | 2 +- src/game/game_instance.hpp | 2 +- src/game/game_scanner.cpp | 6 +++--- src/game/game_scanner.hpp | 4 ++-- src/script/script_config.cpp | 8 +++----- src/script/script_config.hpp | 7 +++---- src/script/script_instance.hpp | 2 +- src/settings.cpp | 4 ++-- 20 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp index fce9c2059c..ae19439754 100644 --- a/src/ai/ai.hpp +++ b/src/ai/ai.hpp @@ -120,9 +120,9 @@ public: /** Wrapper function for AIScanner::GetUniqueAIInfoList */ static const ScriptInfoList *GetUniqueInfoList(); /** Wrapper function for AIScanner::FindInfo */ - static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match); + static class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match); /** Wrapper function for AIScanner::FindLibrary */ - static class AILibrary *FindLibrary(const char *library, int version); + static class AILibrary *FindLibrary(const std::string &library, int version); /** * Rescans all searchpaths for available AIs. If a used AI is no longer diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp index a1c6479952..7493556736 100644 --- a/src/ai/ai_config.cpp +++ b/src/ai/ai_config.cpp @@ -33,7 +33,7 @@ class AIInfo *AIConfig::GetInfo() const return static_cast(ScriptConfig::GetInfo()); } -ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match) +ScriptInfo *AIConfig::FindInfo(const std::string &name, int version, bool force_exact_match) { return static_cast(AI::FindInfo(name, version, force_exact_match)); } diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp index a0f98d2187..b64020b4f0 100644 --- a/src/ai/ai_config.hpp +++ b/src/ai/ai_config.hpp @@ -41,7 +41,7 @@ public: bool ResetInfo(bool force_exact_match); protected: - ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override; + ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override; }; #endif /* AI_CONFIG_HPP */ diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index feeeeb0162..eb45cd1e56 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -309,12 +309,12 @@ return AI::scanner_info->GetUniqueInfoList(); } -/* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match) +/* static */ AIInfo *AI::FindInfo(const std::string &name, int version, bool force_exact_match) { return AI::scanner_info->FindInfo(name, version, force_exact_match); } -/* static */ AILibrary *AI::FindLibrary(const char *library, int version) +/* static */ AILibrary *AI::FindLibrary(const std::string &library, int version) { return AI::scanner_library->FindLibrary(library, version); } diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 411afe3aa0..5f8ac9d164 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -88,7 +88,7 @@ int AIInstance::GetSetting(const char *name) return AIConfig::GetConfig(_current_company)->GetSetting(name); } -ScriptInfo *AIInstance::FindLibrary(const char *library, int version) +ScriptInfo *AIInstance::FindLibrary(const std::string &library, int version) { return (ScriptInfo *)AI::FindLibrary(library, version); } diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp index 2cdabd9913..12b5159425 100644 --- a/src/ai/ai_instance.hpp +++ b/src/ai/ai_instance.hpp @@ -24,7 +24,7 @@ public: void Initialize(class AIInfo *info); int GetSetting(const char *name) override; - ScriptInfo *FindLibrary(const char *library, int version) override; + ScriptInfo *FindLibrary(const std::string &library, int version) override; private: void RegisterAPI() override; diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp index 150aafd34d..e37f2ed6c4 100644 --- a/src/ai/ai_scanner.cpp +++ b/src/ai/ai_scanner.cpp @@ -92,10 +92,10 @@ AIInfo *AIScannerInfo::SelectRandomAI() const #undef GetAIInfo } -AIInfo *AIScannerInfo::FindInfo(const char *name, int version, bool force_exact_match) +AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match) { if (this->info_list.size() == 0) return nullptr; - if (name == nullptr) return nullptr; + if (name.empty()) return nullptr; if (version == -1) { /* We want to load the latest version of this AI; so find it */ @@ -145,7 +145,7 @@ void AIScannerLibrary::RegisterAPI(class Squirrel *engine) AILibrary::RegisterAPI(engine); } -AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version) +AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version) { /* Internally we store libraries as 'library.version' */ std::string library_name = fmt::format("{}.{}", library, version); diff --git a/src/ai/ai_scanner.hpp b/src/ai/ai_scanner.hpp index 4a6a065142..a2c8a7280e 100644 --- a/src/ai/ai_scanner.hpp +++ b/src/ai/ai_scanner.hpp @@ -32,7 +32,7 @@ public: * @param force_exact_match Only match name+version, never latest. * @return nullptr if no match found, otherwise the AI that matched. */ - class AIInfo *FindInfo(const char *name, int version, bool force_exact_match); + class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match); /** * Set the Dummy AI. @@ -60,7 +60,7 @@ public: * @param version The version the library should have. * @return The library if found, nullptr otherwise. */ - class AILibrary *FindLibrary(const char *library, int version); + class AILibrary *FindLibrary(const std::string &library, int version); protected: std::string GetScriptName(ScriptInfo *info) override; diff --git a/src/game/game.hpp b/src/game/game.hpp index 9e92130f10..3c8fcdad92 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -91,9 +91,9 @@ public: /** Wrapper function for GameScanner::GetUniqueInfoList */ static const ScriptInfoList *GetUniqueInfoList(); /** Wrapper function for GameScannerInfo::FindInfo */ - static class GameInfo *FindInfo(const char *name, int version, bool force_exact_match); + static class GameInfo *FindInfo(const std::string &name, int version, bool force_exact_match); /** Wrapper function for GameScanner::FindLibrary */ - static class GameLibrary *FindLibrary(const char *library, int version); + static class GameLibrary *FindLibrary(const std::string &library, int version); /** * Get the current active instance. diff --git a/src/game/game_config.cpp b/src/game/game_config.cpp index 89283129e7..28b6d281b0 100644 --- a/src/game/game_config.cpp +++ b/src/game/game_config.cpp @@ -32,7 +32,7 @@ class GameInfo *GameConfig::GetInfo() const return static_cast(ScriptConfig::GetInfo()); } -ScriptInfo *GameConfig::FindInfo(const char *name, int version, bool force_exact_match) +ScriptInfo *GameConfig::FindInfo(const std::string &name, int version, bool force_exact_match) { return static_cast(Game::FindInfo(name, version, force_exact_match)); } diff --git a/src/game/game_config.hpp b/src/game/game_config.hpp index a01128e671..41385035d2 100644 --- a/src/game/game_config.hpp +++ b/src/game/game_config.hpp @@ -40,7 +40,7 @@ public: bool ResetInfo(bool force_exact_match); protected: - ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override; + ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override; }; #endif /* GAME_CONFIG_HPP */ diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index a4e1e64ddc..eff3055f96 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -239,12 +239,12 @@ return Game::scanner_info->GetUniqueInfoList(); } -/* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match) +/* static */ GameInfo *Game::FindInfo(const std::string &name, int version, bool force_exact_match) { return Game::scanner_info->FindInfo(name, version, force_exact_match); } -/* static */ GameLibrary *Game::FindLibrary(const char *library, int version) +/* static */ GameLibrary *Game::FindLibrary(const std::string &library, int version) { return Game::scanner_library->FindLibrary(library, version); } diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp index 8fcc6252de..36c3b984c8 100644 --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -58,7 +58,7 @@ int GameInstance::GetSetting(const char *name) return GameConfig::GetConfig()->GetSetting(name); } -ScriptInfo *GameInstance::FindLibrary(const char *library, int version) +ScriptInfo *GameInstance::FindLibrary(const std::string &library, int version) { return (ScriptInfo *)Game::FindLibrary(library, version); } diff --git a/src/game/game_instance.hpp b/src/game/game_instance.hpp index 84cb20ac5a..4b5e1b0452 100644 --- a/src/game/game_instance.hpp +++ b/src/game/game_instance.hpp @@ -24,7 +24,7 @@ public: void Initialize(class GameInfo *info); int GetSetting(const char *name) override; - ScriptInfo *FindLibrary(const char *library, int version) override; + ScriptInfo *FindLibrary(const std::string &library, int version) override; private: void RegisterAPI() override; diff --git a/src/game/game_scanner.cpp b/src/game/game_scanner.cpp index 85b2a77ea5..465392e698 100644 --- a/src/game/game_scanner.cpp +++ b/src/game/game_scanner.cpp @@ -33,10 +33,10 @@ void GameScannerInfo::RegisterAPI(class Squirrel *engine) GameInfo::RegisterAPI(engine); } -GameInfo *GameScannerInfo::FindInfo(const char *name, int version, bool force_exact_match) +GameInfo *GameScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match) { if (this->info_list.size() == 0) return nullptr; - if (name == nullptr) return nullptr; + if (name.empty()) return nullptr; if (version == -1) { /* We want to load the latest version of this Game script; so find it */ @@ -86,7 +86,7 @@ void GameScannerLibrary::RegisterAPI(class Squirrel *engine) GameLibrary::RegisterAPI(engine); } -GameLibrary *GameScannerLibrary::FindLibrary(const char *library, int version) +GameLibrary *GameScannerLibrary::FindLibrary(const std::string &library, int version) { /* Internally we store libraries as 'library.version' */ std::string library_name = fmt::format("{}.{}", library, version); diff --git a/src/game/game_scanner.hpp b/src/game/game_scanner.hpp index c0628fc6a7..027649b1ad 100644 --- a/src/game/game_scanner.hpp +++ b/src/game/game_scanner.hpp @@ -23,7 +23,7 @@ public: * @param force_exact_match Only match name+version, never latest. * @return nullptr if no match found, otherwise the game script that matched. */ - class GameInfo *FindInfo(const char *name, int version, bool force_exact_match); + class GameInfo *FindInfo(const std::string &name, int version, bool force_exact_match); protected: std::string GetScriptName(ScriptInfo *info) override; @@ -44,7 +44,7 @@ public: * @param version The version the library should have. * @return The library if found, nullptr otherwise. */ - class GameLibrary *FindLibrary(const char *library, int version); + class GameLibrary *FindLibrary(const std::string &library, int version); protected: std::string GetScriptName(ScriptInfo *info) override; diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 0addbdd35f..6e9514e140 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -19,8 +19,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match, bool is_random) { - free(this->name); - this->name = (name == nullptr) ? nullptr : stredup(name); + this->name = (name == nullptr) ? "" : name; this->info = (name == nullptr) ? nullptr : this->FindInfo(this->name, version, force_exact_match); this->version = (info == nullptr) ? -1 : info->GetVersion(); this->is_random = is_random; @@ -44,7 +43,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match, ScriptConfig::ScriptConfig(const ScriptConfig *config) { - this->name = (config->name == nullptr) ? nullptr : stredup(config->name); + this->name = config->name; this->info = config->info; this->version = config->version; this->is_random = config->is_random; @@ -60,7 +59,6 @@ ScriptConfig::ScriptConfig(const ScriptConfig *config) ScriptConfig::~ScriptConfig() { - free(this->name); this->ResetSettings(); this->to_load_data.reset(); } @@ -156,7 +154,7 @@ bool ScriptConfig::IsRandom() const return this->is_random; } -const char *ScriptConfig::GetName() const +const std::string &ScriptConfig::GetName() const { return this->name; } diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 274a8f2058..22d5832fd7 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -60,7 +60,6 @@ protected: public: ScriptConfig() : - name(nullptr), version(-1), info(nullptr), is_random(false), @@ -159,7 +158,7 @@ public: /** * Get the name of the Script. */ - const char *GetName() const; + const std::string &GetName() const; /** * Get the version of the Script. @@ -190,7 +189,7 @@ public: ScriptInstance::ScriptData *GetToLoadData(); protected: - const char *name; ///< Name of the Script + std::string name; ///< Name of the Script int version; ///< Version of the Script class ScriptInfo *info; ///< ScriptInfo object for related to this Script version SettingValueList settings; ///< List with all setting=>value pairs that are configure for this Script @@ -207,7 +206,7 @@ protected: * This function should call back to the Scanner in charge of this Config, * to find the ScriptInfo belonging to a name+version. */ - virtual ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) = 0; + virtual ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) = 0; }; #endif /* SCRIPT_CONFIG_HPP */ diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 4e98b8df7e..c9acf4c80a 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -70,7 +70,7 @@ public: * @param version The version the library should have. * @return The library if found, nullptr otherwise. */ - virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0; + virtual class ScriptInfo *FindLibrary(const std::string &library, int version) = 0; /** * A script in multiplayer waits for the server to handle its DoCommand. diff --git a/src/settings.cpp b/src/settings.cpp index d650d5594d..098df6761a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1080,7 +1080,7 @@ static void AISaveConfig(IniFile &ini, const char *grpname) for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - const char *name; + std::string name; std::string value = config->SettingsToString(); if (config->HasScript()) { @@ -1102,7 +1102,7 @@ static void GameSaveConfig(IniFile &ini, const char *grpname) group->Clear(); GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - const char *name; + std::string name; std::string value = config->SettingsToString(); if (config->HasScript()) { From 9f2fc860ada61e719d97e877474f0dea68acc329 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 5 May 2023 21:59:50 +0200 Subject: [PATCH 27/58] Codechange: use std::optional for changing the script over char * --- src/ai/ai_core.cpp | 4 ++-- src/game/game_core.cpp | 4 ++-- src/openttd.cpp | 2 +- src/saveload/ai_sl.cpp | 8 ++++---- src/saveload/game_sl.cpp | 6 +++--- src/script/script_config.cpp | 10 +++++++--- src/script/script_config.hpp | 2 +- src/script/script_gui.cpp | 2 +- src/settings.cpp | 8 ++++---- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index eb45cd1e56..0660dfe0f5 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -208,7 +208,7 @@ if (_settings_game.ai_config[c] != nullptr && _settings_game.ai_config[c]->HasScript()) { if (!_settings_game.ai_config[c]->ResetInfo(true)) { Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName()); - _settings_game.ai_config[c]->Change(nullptr); + _settings_game.ai_config[c]->Change(std::nullopt); if (Company::IsValidAiID(c)) { /* The code belonging to an already running AI was deleted. We can only do * one thing here to keep everything sane and that is kill the AI. After @@ -225,7 +225,7 @@ if (_settings_newgame.ai_config[c] != nullptr && _settings_newgame.ai_config[c]->HasScript()) { if (!_settings_newgame.ai_config[c]->ResetInfo(false)) { Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName()); - _settings_newgame.ai_config[c]->Change(nullptr); + _settings_newgame.ai_config[c]->Change(std::nullopt); } } } diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index eff3055f96..c67446f7cc 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -175,7 +175,7 @@ if (_settings_game.game_config != nullptr && _settings_game.game_config->HasScript()) { if (!_settings_game.game_config->ResetInfo(true)) { Debug(script, 0, "After a reload, the GameScript by the name '{}' was no longer found, and removed from the list.", _settings_game.game_config->GetName()); - _settings_game.game_config->Change(nullptr); + _settings_game.game_config->Change(std::nullopt); if (Game::instance != nullptr) { delete Game::instance; Game::instance = nullptr; @@ -188,7 +188,7 @@ if (_settings_newgame.game_config != nullptr && _settings_newgame.game_config->HasScript()) { if (!_settings_newgame.game_config->ResetInfo(false)) { Debug(script, 0, "After a reload, the GameScript by the name '{}' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName()); - _settings_newgame.game_config->Change(nullptr); + _settings_newgame.game_config->Change(std::nullopt); } } } diff --git a/src/openttd.cpp b/src/openttd.cpp index 97face4e6c..b048f1c6c9 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -373,7 +373,7 @@ void MakeNewgameSettingsLive() if (_settings_newgame.ai_config[c] != nullptr) { _settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]); if (!AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->HasScript()) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(std::nullopt); } } } diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp index 90e96ba9a2..927c130470 100644 --- a/src/saveload/ai_sl.cpp +++ b/src/saveload/ai_sl.cpp @@ -66,7 +66,7 @@ struct AIPLChunkHandler : ChunkHandler { /* Free all current data */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(std::nullopt); } CompanyID index; @@ -85,13 +85,13 @@ struct AIPLChunkHandler : ChunkHandler { AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME); if (_ai_saveload_name.empty()) { /* A random AI. */ - config->Change(nullptr, -1, false, true); + config->Change(std::nullopt, -1, false, true); } else { - config->Change(_ai_saveload_name.c_str(), _ai_saveload_version, false, _ai_saveload_is_random); + config->Change(_ai_saveload_name, _ai_saveload_version, false, _ai_saveload_is_random); if (!config->HasScript()) { /* No version of the AI available that can load the data. Try to load the * latest version of the AI instead. */ - config->Change(_ai_saveload_name.c_str(), -1, false, _ai_saveload_is_random); + config->Change(_ai_saveload_name, -1, false, _ai_saveload_is_random); if (!config->HasScript()) { if (_ai_saveload_name.compare("%_dummy") != 0) { Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index 9e938bafb3..1eb6539710 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -62,7 +62,7 @@ struct GSDTChunkHandler : ChunkHandler { const std::vector slt = SlCompatTableHeader(_game_script_desc, _game_script_sl_compat); /* Free all current data */ - GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr); + GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(std::nullopt); if (SlIterateArray() == -1) return; @@ -77,11 +77,11 @@ struct GSDTChunkHandler : ChunkHandler { GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); if (!_game_saveload_name.empty()) { - config->Change(_game_saveload_name.c_str(), _game_saveload_version, false, _game_saveload_is_random); + config->Change(_game_saveload_name, _game_saveload_version, false, _game_saveload_is_random); if (!config->HasScript()) { /* No version of the GameScript available that can load the data. Try to load the * latest version of the GameScript instead. */ - config->Change(_game_saveload_name.c_str(), -1, false, _game_saveload_is_random); + config->Change(_game_saveload_name, -1, false, _game_saveload_is_random); if (!config->HasScript()) { if (_game_saveload_name.compare("%_dummy") != 0) { Debug(script, 0, "The savegame has an GameScript by the name '{}', version {} which is no longer available.", _game_saveload_name, _game_saveload_version); diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 6e9514e140..148279c902 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -17,10 +17,14 @@ #include "../safeguards.h" -void ScriptConfig::Change(const char *name, int version, bool force_exact_match, bool is_random) +void ScriptConfig::Change(std::optional name, int version, bool force_exact_match, bool is_random) { - this->name = (name == nullptr) ? "" : name; - this->info = (name == nullptr) ? nullptr : this->FindInfo(this->name, version, force_exact_match); + if (name.has_value()) { + this->name = std::move(name.value()); + this->info = this->FindInfo(this->name, version, force_exact_match); + } else { + this->info = nullptr; + } this->version = (info == nullptr) ? -1 : info->GetVersion(); this->is_random = is_random; this->config_list.reset(); diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 22d5832fd7..cc9e62f702 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -83,7 +83,7 @@ public: * as specified. If false any compatible version is ok. * @param is_random Is the Script chosen randomly? */ - void Change(const char *name, int version = -1, bool force_exact_match = false, bool is_random = false); + void Change(std::optional name, int version = -1, bool force_exact_match = false, bool is_random = false); /** * Get the ScriptInfo linked to this ScriptConfig. diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index 2437d22742..c47bbadee0 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -172,7 +172,7 @@ struct ScriptListWindow : public Window { void ChangeScript() { if (this->selected == -1) { - GetConfig(slot)->Change(nullptr); + GetConfig(slot)->Change(std::nullopt); } else { ScriptInfoList::const_iterator it = this->info_list->cbegin(); std::advance(it, this->selected); diff --git a/src/settings.cpp b/src/settings.cpp index 098df6761a..158945a79a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -869,7 +869,7 @@ static void AILoadConfig(IniFile &ini, const char *grpname) /* Clean any configured AI */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(nullptr); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(std::nullopt); } /* If no group exists, return */ @@ -879,7 +879,7 @@ static void AILoadConfig(IniFile &ini, const char *grpname) for (item = group->item; c < MAX_COMPANIES && item != nullptr; c++, item = item->next) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - config->Change(item->name.c_str()); + config->Change(item->name); if (!config->HasScript()) { if (item->name != "none") { Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item->name); @@ -896,7 +896,7 @@ static void GameLoadConfig(IniFile &ini, const char *grpname) IniItem *item; /* Clean any configured GameScript */ - GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(nullptr); + GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(std::nullopt); /* If no group exists, return */ if (group == nullptr) return; @@ -906,7 +906,7 @@ static void GameLoadConfig(IniFile &ini, const char *grpname) GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - config->Change(item->name.c_str()); + config->Change(item->name); if (!config->HasScript()) { if (item->name != "none") { Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item->name); From 3453c03a1781314a182828948af091b675002cc4 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 08:15:22 +0200 Subject: [PATCH 28/58] Codechange: use fmt::format to create dummy scripts --- src/script/script_info_dummy.cpp | 102 ++++++++++++++++--------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/src/script/script_info_dummy.cpp b/src/script/script_info_dummy.cpp index 9438b77f09..70447b4b97 100644 --- a/src/script/script_info_dummy.cpp +++ b/src/script/script_info_dummy.cpp @@ -12,6 +12,7 @@ #include "../string_func.h" #include "../strings_func.h" +#include "../3rdparty/fmt/format.h" #include "../safeguards.h" @@ -27,24 +28,21 @@ /** Run the dummy info.nut. */ void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir) { - char dummy_script[4096]; - char *dp = dummy_script; - dp += seprintf(dp, lastof(dummy_script), "class Dummy%s extends %sInfo {\n", type, type); - dp += seprintf(dp, lastof(dummy_script), "function GetAuthor() { return \"OpenTTD Developers Team\"; }\n"); - dp += seprintf(dp, lastof(dummy_script), "function GetName() { return \"Dummy%s\"; }\n", type); - dp += seprintf(dp, lastof(dummy_script), "function GetShortName() { return \"DUMM\"; }\n"); - dp += seprintf(dp, lastof(dummy_script), "function GetDescription() { return \"A Dummy %s that is loaded when your %s/ dir is empty\"; }\n", type, dir); - dp += seprintf(dp, lastof(dummy_script), "function GetVersion() { return 1; }\n"); - dp += seprintf(dp, lastof(dummy_script), "function GetDate() { return \"2008-07-26\"; }\n"); - dp += seprintf(dp, lastof(dummy_script), "function CreateInstance() { return \"Dummy%s\"; }\n", type); - dp += seprintf(dp, lastof(dummy_script), "} RegisterDummy%s(Dummy%s());\n", type, type); - - const SQChar *sq_dummy_script = dummy_script; + std::string dummy_script = fmt::format( + "class Dummy{0} extends {0}Info {{\n" + "function GetAuthor() {{ return \"OpenTTD Developers Team\"; }}\n" + "function GetName() {{ return \"Dummy{0}\"; }}\n" + "function GetShortName() {{ return \"DUMM\"; }}\n" + "function GetDescription() {{ return \"A Dummy {0} that is loaded when your {1}/ dir is empty\"; }}\n" + "function GetVersion() {{ return 1; }}\n" + "function GetDate() {{ return \"2008-07-26\"; }}\n" + "function CreateInstance() {{ return \"Dummy{0}\"; }}\n" + "}} RegisterDummy{0}(Dummy{0}());\n", type, dir); sq_pushroottable(vm); /* Load and run the script */ - if (SQ_SUCCEEDED(sq_compilebuffer(vm, sq_dummy_script, strlen(sq_dummy_script), "dummy", SQTrue))) { + if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) { sq_push(vm, -2); if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) { sq_pop(vm, 1); @@ -54,52 +52,56 @@ void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir) NOT_REACHED(); } +/** + * Split the given message on newlines ('\n') and escape quotes and (back)slashes, + * so they can be properly interpreted as string constants by the Squirrel compiler. + * @param message The message that we want to sanitize for use in Squirrel code. + * @return Vector with sanitized strings to use as string constant in Squirrel code. + */ +static std::vector EscapeQuotesAndSlashesAndSplitOnNewLines(const std::string &message) +{ + std::vector messages; + + std::string safe_message; + for (auto c : message) { + if (c == '\n') { + messages.emplace_back(std::move(safe_message)); + continue; + } + + if (c == '"' || c == '\\') safe_message.push_back('\\'); + safe_message.push_back(c); + } + messages.emplace_back(std::move(safe_message)); + return messages; +} + /** Run the dummy AI and let it generate an error message. */ void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type) { /* We want to translate the error message. * We do this in three steps: - * 1) We get the error message + * 1) We get the error message, escape quotes and slashes, and split on + * newlines because Log.Error terminates passed strings at newlines. */ - char error_message[1024]; - GetString(error_message, string, lastof(error_message)); - - /* Make escapes for all quotes and slashes. */ - char safe_error_message[1024]; - char *q = safe_error_message; - for (const char *p = error_message; *p != '\0' && q < lastof(safe_error_message) - 2; p++, q++) { - if (*p == '"' || *p == '\\') *q++ = '\\'; - *q = *p; - } - *q = '\0'; + std::string error_message = GetString(string); + std::vector messages = EscapeQuotesAndSlashesAndSplitOnNewLines(error_message); /* 2) We construct the AI's code. This is done by merging a header, body and footer */ - char dummy_script[4096]; - char *dp = dummy_script; - dp += seprintf(dp, lastof(dummy_script), "class Dummy%s extends %sController {\n function Start()\n {\n", type, type); - - /* As special trick we need to split the error message on newlines and - * emit each newline as a separate error printing string. */ - char *newline; - char *p = safe_error_message; - do { - newline = strchr(p, '\n'); - if (newline != nullptr) *newline = '\0'; - - dp += seprintf(dp, lastof(dummy_script), " %sLog.Error(\"%s\");\n", type, p); - p = newline + 1; - } while (newline != nullptr); - - strecpy(dp, " }\n}\n", lastof(dummy_script)); - - /* 3) We translate the error message in the character format that Squirrel wants. - * We can use the fact that the wchar string printing also uses %s to print - * old style char strings, which is what was generated during the script generation. */ - const SQChar *sq_dummy_script = dummy_script; + std::string dummy_script; + auto back_inserter = std::back_inserter(dummy_script); + /* Just a rough ballpark estimate. */ + dummy_script.reserve(error_message.size() + 128 + 64 * messages.size()); + + fmt::format_to(back_inserter, "class Dummy{0} extends {0}Controller {{\n function Start()\n {{\n", type); + for (std::string &message : messages) { + fmt::format_to(back_inserter, " {}Log.Error(\"{}\");\n", type, message); + } + dummy_script += " }\n}\n"; - /* And finally we load and run the script */ + /* 3) Finally we load and run the script */ sq_pushroottable(vm); - if (SQ_SUCCEEDED(sq_compilebuffer(vm, sq_dummy_script, strlen(sq_dummy_script), "dummy", SQTrue))) { + if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) { sq_push(vm, -2); if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) { sq_pop(vm, 1); From e035705239059245720fe784cb618fa8d5d2b56b Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 00:04:10 +0200 Subject: [PATCH 29/58] Codechange: introduce and use std::string variant of sq_throwerror --- src/3rdparty/squirrel/include/squirrel.h | 3 ++- src/3rdparty/squirrel/squirrel/sqapi.cpp | 4 ++-- src/script/api/script_controller.cpp | 12 +++--------- src/script/script_info.cpp | 21 ++++++--------------- src/script/script_instance.cpp | 8 ++++---- src/script/squirrel.hpp | 2 +- 6 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/3rdparty/squirrel/include/squirrel.h b/src/3rdparty/squirrel/include/squirrel.h index 7dfdaed9ad..d5ec13c119 100644 --- a/src/3rdparty/squirrel/include/squirrel.h +++ b/src/3rdparty/squirrel/include/squirrel.h @@ -307,7 +307,8 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); -SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len = -1); +static inline SQRESULT sq_throwerror(HSQUIRRELVM v, const std::string_view err) { return sq_throwerror(v, err.data(), err.size()); } void sq_reseterror(HSQUIRRELVM v); void sq_getlasterror(HSQUIRRELVM v); diff --git a/src/3rdparty/squirrel/squirrel/sqapi.cpp b/src/3rdparty/squirrel/squirrel/sqapi.cpp index 0be573bcc4..d5fd9dd38b 100644 --- a/src/3rdparty/squirrel/squirrel/sqapi.cpp +++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp @@ -933,9 +933,9 @@ void sq_resetobject(HSQOBJECT *po) po->_unVal.pUserPointer=nullptr;po->_type=OT_NULL; } -SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len) { - v->_lasterror=SQString::Create(_ss(v),err); + v->_lasterror=SQString::Create(_ss(v),err, len); return -1; } diff --git a/src/script/api/script_controller.cpp b/src/script/api/script_controller.cpp index b226362376..b083fccddb 100644 --- a/src/script/api/script_controller.cpp +++ b/src/script/api/script_controller.cpp @@ -104,9 +104,7 @@ ScriptController::ScriptController(CompanyID company) : ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version); if (lib == nullptr) { - char error[1024]; - seprintf(error, lastof(error), "couldn't find library '%s' with version %d", library, version); - throw sq_throwerror(vm, error); + throw sq_throwerror(vm, fmt::format("couldn't find library '{}' with version {}", library, version)); } /* Internally we store libraries as 'library.version' */ @@ -133,9 +131,7 @@ ScriptController::ScriptController(CompanyID company) : sq_newclass(vm, SQFalse); /* Load the library */ if (!engine->LoadScript(vm, lib->GetMainScript(), false)) { - char error[1024]; - seprintf(error, lastof(error), "there was a compile error when importing '%s' version %d", library, version); - throw sq_throwerror(vm, error); + throw sq_throwerror(vm, fmt::format("there was a compile error when importing '{}' version {}", library, version)); } /* Create the fake class */ sq_newslot(vm, -3, SQFalse); @@ -152,9 +148,7 @@ ScriptController::ScriptController(CompanyID company) : } sq_pushstring(vm, lib->GetInstanceName(), -1); if (SQ_FAILED(sq_get(vm, -2))) { - char error[1024]; - seprintf(error, lastof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version); - throw sq_throwerror(vm, error); + throw sq_throwerror(vm, fmt::format("unable to find class '{}' in the library '{}' version {}", lib->GetInstanceName(), library, version)); } HSQOBJECT obj; sq_getstackobj(vm, -1, &obj); diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 9f815f3e21..77097ddd21 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -14,6 +14,7 @@ #include "script_info.hpp" #include "script_scanner.hpp" +#include "../3rdparty/fmt/format.h" #include "../safeguards.h" @@ -32,9 +33,7 @@ ScriptInfo::~ScriptInfo() bool ScriptInfo::CheckMethod(const char *name) const { if (!this->engine->MethodExists(*this->SQ_instance, name)) { - char error[1024]; - seprintf(error, lastof(error), "your info.nut/library.nut doesn't have the method '%s'", name); - this->engine->ThrowError(error); + this->engine->ThrowError(fmt::format("your info.nut/library.nut doesn't have the method '{}'", name)); return false; } return true; @@ -168,9 +167,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) config.flags = (ScriptConfigFlags)res; items |= 0x100; } else { - char error[1024]; - seprintf(error, lastof(error), "unknown setting property '%s'", key); - this->engine->ThrowError(error); + this->engine->ThrowError(fmt::format("unknown setting property '{}'", key)); return SQ_ERROR; } @@ -181,9 +178,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) /* Don't allow both random_deviation and SCRIPTCONFIG_RANDOM to * be set for the same config item. */ if ((items & 0x200) != 0 && (config.flags & SCRIPTCONFIG_RANDOM) != 0) { - char error[1024]; - seprintf(error, lastof(error), "Setting both random_deviation and SCRIPTCONFIG_RANDOM is not allowed"); - this->engine->ThrowError(error); + this->engine->ThrowError("Setting both random_deviation and SCRIPTCONFIG_RANDOM is not allowed"); return SQ_ERROR; } /* Reset the bit for random_deviation as it's optional. */ @@ -192,9 +187,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) /* Make sure all properties are defined */ uint mask = (config.flags & SCRIPTCONFIG_BOOLEAN) ? 0x1F3 : 0x1FF; if (items != mask) { - char error[1024]; - seprintf(error, lastof(error), "please define all properties of a setting (min/max not allowed for booleans)"); - this->engine->ThrowError(error); + this->engine->ThrowError("please define all properties of a setting (min/max not allowed for booleans)"); return SQ_ERROR; } @@ -214,9 +207,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm) } if (config == nullptr) { - char error[1024]; - seprintf(error, lastof(error), "Trying to add labels for non-defined setting '%s'", setting_name); - this->engine->ThrowError(error); + this->engine->ThrowError(fmt::format("Trying to add labels for non-defined setting '{}'", setting_name)); return SQ_ERROR; } if (!config->labels.empty()) return SQ_ERROR; diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index c04d3c2fec..b970aa7094 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -101,7 +101,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na ScriptObject::SetAllowDoCommand(true); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage().c_str()); + this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } @@ -226,7 +226,7 @@ void ScriptInstance::GameLoop() this->callback = e.GetSuspendCallback(); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage().c_str()); + this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } @@ -247,7 +247,7 @@ void ScriptInstance::GameLoop() this->callback = e.GetSuspendCallback(); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage().c_str()); + this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } @@ -505,7 +505,7 @@ void ScriptInstance::Save() /* If we don't mark the script as dead here cleaning up the squirrel * stack could throw Script_FatalError again. */ this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage().c_str()); + this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); SaveEmpty(); /* We can't kill the script here, so mark it as crashed (not dead) and diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index f9471ff14b..34325c7a3d 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -234,7 +234,7 @@ public: /** * Throw a Squirrel error that will be nicely displayed to the user. */ - void ThrowError(const char *error) { sq_throwerror(this->vm, error); } + void ThrowError(const std::string_view error) { sq_throwerror(this->vm, error); } /** * Release a SQ object. From 552d2f71a2ecabac46ba94f6c0e5da7fdc125c7b Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 09:53:57 +0200 Subject: [PATCH 30/58] Codechange: use std::string for script library category --- src/ai/ai_info.cpp | 7 +------ src/ai/ai_info.hpp | 7 +++---- src/game/game_info.cpp | 7 +------ src/game/game_info.hpp | 7 +++---- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index 29dfdf81f4..fac36129a3 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -129,11 +129,6 @@ bool AIInfo::CanLoadFromVersion(int version) const } -AILibrary::~AILibrary() -{ - free(this->category); -} - /* static */ void AILibrary::RegisterAPI(Squirrel *engine) { /* Create the AILibrary class, and add the RegisterLibrary function */ @@ -154,7 +149,7 @@ AILibrary::~AILibrary() } /* Cache the category */ - if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { + if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp index a87b6cc36c..df8e6b65d7 100644 --- a/src/ai/ai_info.hpp +++ b/src/ai/ai_info.hpp @@ -56,8 +56,7 @@ private: /** All static information from an AI library like name, version, etc. */ class AILibrary : public ScriptInfo { public: - AILibrary() : ScriptInfo(), category(nullptr) {}; - ~AILibrary(); + AILibrary() : ScriptInfo() {}; /** * Register the functions of this class. @@ -72,10 +71,10 @@ public: /** * Get the category this library is in. */ - const char *GetCategory() const { return this->category; } + const std::string &GetCategory() const { return this->category; } private: - const char *category; ///< The category this library is in. + std::string category; ///< The category this library is in. }; #endif /* AI_INFO_HPP */ diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp index 2144ebd377..88347c5157 100644 --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -99,11 +99,6 @@ bool GameInfo::CanLoadFromVersion(int version) const } -GameLibrary::~GameLibrary() -{ - free(this->category); -} - /* static */ void GameLibrary::RegisterAPI(Squirrel *engine) { /* Create the GameLibrary class, and add the RegisterLibrary function */ @@ -124,7 +119,7 @@ GameLibrary::~GameLibrary() } /* Cache the category */ - if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { + if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } diff --git a/src/game/game_info.hpp b/src/game/game_info.hpp index 76dbfd546f..d5dd48701d 100644 --- a/src/game/game_info.hpp +++ b/src/game/game_info.hpp @@ -48,8 +48,7 @@ private: /** All static information from an Game library like name, version, etc. */ class GameLibrary : public ScriptInfo { public: - GameLibrary() : ScriptInfo(), category(nullptr) {}; - ~GameLibrary(); + GameLibrary() : ScriptInfo() {}; /** * Register the functions of this class. @@ -64,10 +63,10 @@ public: /** * Get the category this library is in. */ - const char *GetCategory() const { return this->category; } + const std::string &GetCategory() const { return this->category; } private: - const char *category; ///< The category this library is in. + std::string category; ///< The category this library is in. }; #endif /* GAME_INFO_HPP */ From 48825e1a8e258b1aca337b5e799c30223b2f271b Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 12:44:47 +0200 Subject: [PATCH 31/58] Codechange: rewrite script string-to-settings conversion to C++ --- src/script/script_config.cpp | 39 +++++++++++++++++------------------- src/script/script_config.hpp | 2 +- src/script/script_info.cpp | 2 +- src/script/script_info.hpp | 2 +- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 148279c902..d86191b5f7 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -14,6 +14,7 @@ #include "api/script_object.hpp" #include "../textfile_gui.h" #include "../string_func.h" +#include #include "../safeguards.h" @@ -102,7 +103,7 @@ int ScriptConfig::GetSetting(const std::string &name) const return (*it).second; } -void ScriptConfig::SetSetting(const std::string &name, int value) +void ScriptConfig::SetSetting(const std::string_view name, int value) { /* You can only set Script specific settings if an Script is selected. */ if (this->info == nullptr) return; @@ -112,7 +113,7 @@ void ScriptConfig::SetSetting(const std::string &name, int value) value = Clamp(value, config_item->min_value, config_item->max_value); - this->settings[name] = value; + this->settings[std::string{name}] = value; } void ScriptConfig::ResetSettings() @@ -170,28 +171,24 @@ int ScriptConfig::GetVersion() const void ScriptConfig::StringToSettings(const std::string &value) { - char *value_copy = stredup(value.c_str()); - char *s = value_copy; - - while (s != nullptr) { + std::string_view to_process = value; + for (;;) { /* Analyze the string ('name=value,name=value\0') */ - char *item_name = s; - s = strchr(s, '='); - if (s == nullptr) break; - if (*s == '\0') break; - *s = '\0'; - s++; - - char *item_value = s; - s = strchr(s, ','); - if (s != nullptr) { - *s = '\0'; - s++; - } + size_t pos = to_process.find_first_of('='); + if (pos == std::string_view::npos) return; + + std::string_view item_name = to_process.substr(0, pos); + + to_process.remove_prefix(pos + 1); + pos = to_process.find_first_of(','); + int item_value = 0; + std::from_chars(to_process.data(), to_process.data() + std::min(pos, to_process.size()), item_value); + + this->SetSetting(item_name, item_value); - this->SetSetting(item_name, atoi(item_value)); + if (pos == std::string_view::npos) return; + to_process.remove_prefix(pos + 1); } - free(value_copy); } std::string ScriptConfig::SettingsToString() const diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index cc9e62f702..4b809e9602 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -127,7 +127,7 @@ public: /** * Set the value of a setting for this config. */ - void SetSetting(const std::string &name, int value); + void SetSetting(const std::string_view name, int value); /** * Reset all settings to their default value. diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 77097ddd21..8c2554a7ab 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -254,7 +254,7 @@ const ScriptConfigItemList *ScriptInfo::GetConfigList() const return &this->config_list; } -const ScriptConfigItem *ScriptInfo::GetConfigItem(const std::string &name) const +const ScriptConfigItem *ScriptInfo::GetConfigItem(const std::string_view name) const { for (const auto &item : this->config_list) { if (item.name == name) return &item; diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp index cb0e3c04d2..35b35622bb 100644 --- a/src/script/script_info.hpp +++ b/src/script/script_info.hpp @@ -122,7 +122,7 @@ public: /** * Get the description of a certain Script config option. */ - const ScriptConfigItem *GetConfigItem(const std::string &name) const; + const ScriptConfigItem *GetConfigItem(const std::string_view name) const; /** * Set a setting. From 20ff0bccd759226b14a7dfe95a5d1cc734c392f4 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 12:49:28 +0200 Subject: [PATCH 32/58] Codechange: use std::string to store script GUI's break string --- src/script/script_gui.cpp | 6 +++--- src/stringfilter.cpp | 9 +++++++++ src/stringfilter_type.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index c47bbadee0..dab4a28b18 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -696,7 +696,7 @@ struct ScriptDebugWindow : public Window { bool autoscroll; ///< Whether automatically scrolling should be enabled or not. bool show_break_box; ///< Whether the break/debug box is visible. static bool break_check_enabled; ///< Stop an AI when it prints a matching string - static char break_string[MAX_BREAK_STR_STRING_LENGTH]; ///< The string to match to the AI output + static std::string break_string; ///< The string to match to the AI output QueryString break_editbox; ///< Break editbox static StringFilter break_string_filter; ///< Log filter for break. static bool case_sensitive_break_check; ///< Is the matching done case-sensitive @@ -1022,7 +1022,7 @@ struct ScriptDebugWindow : public Window { if (wid != WID_SCRD_BREAK_STR_EDIT_BOX) return; /* Save the current string to static member so it can be restored next time the window is opened. */ - strecpy(this->break_string, this->break_editbox.text.buf, lastof(this->break_string)); + this->break_string = this->break_editbox.text.buf; break_string_filter.SetFilterTerm(this->break_string); } @@ -1098,7 +1098,7 @@ struct ScriptDebugWindow : public Window { }; CompanyID ScriptDebugWindow::script_debug_company = INVALID_COMPANY; -char ScriptDebugWindow::break_string[MAX_BREAK_STR_STRING_LENGTH] = ""; +std::string ScriptDebugWindow::break_string; bool ScriptDebugWindow::break_check_enabled = true; bool ScriptDebugWindow::case_sensitive_break_check = false; StringFilter ScriptDebugWindow::break_string_filter(&ScriptDebugWindow::case_sensitive_break_check); diff --git a/src/stringfilter.cpp b/src/stringfilter.cpp index d15bbcde76..11ce86941d 100644 --- a/src/stringfilter.cpp +++ b/src/stringfilter.cpp @@ -83,6 +83,15 @@ void StringFilter::SetFilterTerm(const char *str) } } +/** + * Set the term to filter on. + * @param str Filter term + */ +void StringFilter::SetFilterTerm(const std::string &str) +{ + this->SetFilterTerm(str.c_str()); +} + /** * Reset the matching state to process a new item. */ diff --git a/src/stringfilter_type.h b/src/stringfilter_type.h index 68b359c9d5..d71a1115d7 100644 --- a/src/stringfilter_type.h +++ b/src/stringfilter_type.h @@ -51,6 +51,7 @@ public: ~StringFilter() { free(this->filter_buffer); } void SetFilterTerm(const char *str); + void SetFilterTerm(const std::string &str); /** * Check whether any filter words were entered. From 98972a0748ea49ba4033a3141e80a4ecd87ceaa7 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 13:22:16 +0200 Subject: [PATCH 33/58] Codechange: use C++ strings for constructing script file paths --- src/fileio.cpp | 2 +- src/fileio_func.h | 2 +- src/fios.cpp | 2 +- src/script/script_scanner.cpp | 7 +++---- src/script/squirrel_std.cpp | 16 ++++++---------- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 2345f7583b..f0bef68d7c 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1253,7 +1253,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r * @return the number of found files, i.e. the number of times that * AddFile returned true. */ -uint FileScanner::Scan(const char *extension, const char *directory, bool recursive) +uint FileScanner::Scan(const char *extension, const std::string &directory, bool recursive) { std::string path(directory); AppendPathSeparator(path); diff --git a/src/fileio_func.h b/src/fileio_func.h index 93b6123dca..a963b8203b 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -42,7 +42,7 @@ public: virtual ~FileScanner() {} uint Scan(const char *extension, Subdirectory sd, bool tars = true, bool recursive = true); - uint Scan(const char *extension, const char *directory, bool recursive = true); + uint Scan(const char *extension, const std::string &directory, bool recursive = true); /** * Add a file with the given filename. diff --git a/src/fios.cpp b/src/fios.cpp index 265a333c61..6cf83341ec 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -410,7 +410,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); if (subdir == NO_DIRECTORY) { - scanner.Scan(nullptr, _fios_path->c_str(), false); + scanner.Scan(nullptr, *_fios_path, false); } else { scanner.Scan(nullptr, subdir, true, true); } diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index 4035dd649a..cb43fb0d0c 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -28,7 +28,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length, this->main_script = filename; this->tar_file = tar_filename; - auto p = this->main_script.rfind(PATHSEPCHAR); + auto p = this->main_script.find_last_of(PATHSEPCHAR); this->main_script.erase(p != std::string::npos ? p + 1 : 0); this->main_script += "main.nut"; @@ -229,12 +229,11 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S checksum.AddFile(tar.first, 0, tar_filename); } } else { - char path[MAX_PATH]; - strecpy(path, info->GetMainScript(), lastof(path)); /* There'll always be at least 1 path separator character in a script * main script name as the search algorithm requires the main script to * be in a subdirectory of the script directory; so //main.nut. */ - *strrchr(path, PATHSEPCHAR) = '\0'; + const std::string &main_script = info->GetMainScript(); + std::string path = main_script.substr(0, main_script.find_last_of(PATHSEPCHAR)); checksum.Scan(".nut", path); } diff --git a/src/script/squirrel_std.cpp b/src/script/squirrel_std.cpp index e04ebf4cc9..abcac023ec 100644 --- a/src/script/squirrel_std.cpp +++ b/src/script/squirrel_std.cpp @@ -53,18 +53,14 @@ SQInteger SquirrelStd::require(HSQUIRRELVM vm) return SQ_ERROR; } - char path[MAX_PATH]; - strecpy(path, si.source, lastof(path)); /* Keep the dir, remove the rest */ - SQChar *s = strrchr(path, PATHSEPCHAR); - if (s != nullptr) { - /* Keep the PATHSEPCHAR there, remove the rest */ - s++; - *s = '\0'; - } - strecat(path, filename, lastof(path)); + std::string path = si.source; + auto p = path.find_last_of(PATHSEPCHAR); + /* Keep the PATHSEPCHAR there, remove the rest */ + if (p != std::string::npos) path.erase(p + 1); + path += filename; #if (PATHSEPCHAR != '/') - for (char *n = path; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR; + std::transform(path.begin(), path.end(), path.begin(), [](char &c) { return c == '/' ? PATHSEPCHAR : c; }); #endif Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); From 77177f7e8b5ca4f43846b5ff4c031d5d7c7bd876 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 5 May 2023 19:31:06 +0200 Subject: [PATCH 34/58] Add: support for std::string parameters in the script API --- cmake/scripts/SquirrelExport.cmake | 2 ++ src/script/squirrel_helper.hpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake index 6fc6f094e6..76fbdd68ab 100644 --- a/cmake/scripts/SquirrelExport.cmake +++ b/cmake/scripts/SquirrelExport.cmake @@ -631,6 +631,8 @@ foreach(LINE IN LISTS SOURCE_LINES) string(APPEND TYPES "a") elseif("${PARAM}" MATCHES "^Text") string(APPEND TYPES ".") + elseif("${PARAM}" MATCHES "^std::string") + string(APPEND TYPES ".") else() string(APPEND TYPES "x") endif() diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index 02b584fe49..ed220b8b40 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -91,6 +91,20 @@ namespace SQConvert { } }; + template <> struct Param { + static inline const std::string Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) + { + /* Convert what-ever there is as parameter to a string */ + sq_tostring(vm, index); + + const SQChar *tmp; + sq_getstring(vm, -1, &tmp); + std::string result = StrMakeValid(tmp); + sq_poptop(vm); + return result; + } + }; + template struct Param> { static inline Array Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) From b24a6bb8f3f12a82265853f8e6f64545ab407be5 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 5 May 2023 19:32:27 +0200 Subject: [PATCH 35/58] Codechange: use std::string for script log calls --- src/script/api/script_controller.cpp | 8 +++----- src/script/api/script_controller.hpp | 4 ++-- src/script/api/script_log.cpp | 11 +++++------ src/script/api/script_log.hpp | 8 ++++---- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/script/api/script_controller.cpp b/src/script/api/script_controller.cpp index b083fccddb..cd39319f0d 100644 --- a/src/script/api/script_controller.cpp +++ b/src/script/api/script_controller.cpp @@ -45,15 +45,13 @@ throw Script_Suspend(ticks, nullptr); } -/* static */ void ScriptController::Break(const char* message) +/* static */ void ScriptController::Break(const std::string &message) { if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return; ScriptObject::GetActiveInstance()->Pause(); - char log_message[1024]; - seprintf(log_message, lastof(log_message), "Break: %s", message); - ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, log_message); + ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, fmt::format("Break: {}", message)); /* Inform script developer that their script has been paused and * needs manual action to continue. */ @@ -64,7 +62,7 @@ } } -/* static */ void ScriptController::Print(bool error_msg, const char *message) +/* static */ void ScriptController::Print(bool error_msg, const std::string &message) { ScriptLog::Log(error_msg ? ScriptLogTypes::LOG_SQ_ERROR : ScriptLogTypes::LOG_SQ_INFO, message); } diff --git a/src/script/api/script_controller.hpp b/src/script/api/script_controller.hpp index ca6bffdf39..f1e7cc9ea5 100644 --- a/src/script/api/script_controller.hpp +++ b/src/script/api/script_controller.hpp @@ -181,7 +181,7 @@ public: * @note gui.ai_developer_tools setting must be enabled or the break is * ignored. */ - static void Break(const char* message); + static void Break(const std::string &message); /** * When Squirrel triggers a print, this function is called. @@ -190,7 +190,7 @@ public: * @param message The message Squirrel logged. * @note Use ScriptLog.Info/Warning/Error instead of 'print'. */ - static void Print(bool error_msg, const char *message); + static void Print(bool error_msg, const std::string &message); /** * Import a library. diff --git a/src/script/api/script_log.cpp b/src/script/api/script_log.cpp index dd3a78c071..adab8f709a 100644 --- a/src/script/api/script_log.cpp +++ b/src/script/api/script_log.cpp @@ -17,22 +17,22 @@ #include "../../safeguards.h" -/* static */ void ScriptLog::Info(const char *message) +/* static */ void ScriptLog::Info(const std::string &message) { ScriptLog::Log(ScriptLogTypes::LOG_INFO, message); } -/* static */ void ScriptLog::Warning(const char *message) +/* static */ void ScriptLog::Warning(const std::string &message) { ScriptLog::Log(ScriptLogTypes::LOG_WARNING, message); } -/* static */ void ScriptLog::Error(const char *message) +/* static */ void ScriptLog::Error(const std::string &message) { ScriptLog::Log(ScriptLogTypes::LOG_ERROR, message); } -/* static */ void ScriptLog::Log(ScriptLogTypes::ScriptLogType level, const char *message) +/* static */ void ScriptLog::Log(ScriptLogTypes::ScriptLogType level, const std::string &message) { ScriptLogTypes::LogData &logdata = ScriptObject::GetLogData(); @@ -43,8 +43,7 @@ line.type = level; /* Cut string after first \n */ - const char *newline = strchr(message, '\n'); - line.text = std::string(message, 0, newline == nullptr ? strlen(message) : newline - message); + line.text = message.substr(0, message.find_first_of('\n')); char logc; diff --git a/src/script/api/script_log.hpp b/src/script/api/script_log.hpp index b2acd1e171..cac45a3067 100644 --- a/src/script/api/script_log.hpp +++ b/src/script/api/script_log.hpp @@ -27,27 +27,27 @@ public: * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ - static void Info(const char *message); + static void Info(const std::string &message); /** * Print a Warning message to the logs. * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ - static void Warning(const char *message); + static void Warning(const std::string &message); /** * Print an Error message to the logs. * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ - static void Error(const char *message); + static void Error(const std::string &message); private: /** * Internal command to log the message in a common way. */ - static void Log(ScriptLogTypes::ScriptLogType level, const char *message); + static void Log(ScriptLogTypes::ScriptLogType level, const std::string &message); }; #endif /* SCRIPT_LOG_HPP */ From bbcb55ebc9c4adf26f01926cb3e9dd28d23a4afa Mon Sep 17 00:00:00 2001 From: Rubidium Date: Fri, 5 May 2023 23:19:35 +0200 Subject: [PATCH 36/58] Codechange: use std::string as script API return type --- src/script/api/script_basestation.cpp | 4 ++-- src/script/api/script_basestation.hpp | 2 +- src/script/api/script_bridge.cpp | 6 +++--- src/script/api/script_bridge.hpp | 2 +- src/script/api/script_cargo.cpp | 13 ++++++------- src/script/api/script_cargo.hpp | 4 ++-- src/script/api/script_client.cpp | 6 +++--- src/script/api/script_client.hpp | 2 +- src/script/api/script_company.cpp | 19 ++++++------------- src/script/api/script_company.hpp | 4 ++-- src/script/api/script_engine.cpp | 4 ++-- src/script/api/script_engine.hpp | 2 +- src/script/api/script_error.cpp | 4 ++-- src/script/api/script_error.hpp | 2 +- src/script/api/script_event_types.cpp | 4 ++-- src/script/api/script_event_types.hpp | 2 +- src/script/api/script_group.cpp | 4 ++-- src/script/api/script_group.hpp | 2 +- src/script/api/script_industry.cpp | 4 ++-- src/script/api/script_industry.hpp | 2 +- src/script/api/script_industrytype.cpp | 4 ++-- src/script/api/script_industrytype.hpp | 2 +- src/script/api/script_newgrf.cpp | 6 +++--- src/script/api/script_newgrf.hpp | 2 +- src/script/api/script_object.cpp | 7 ++----- src/script/api/script_object.hpp | 2 +- src/script/api/script_objecttype.cpp | 4 ++-- src/script/api/script_objecttype.hpp | 2 +- src/script/api/script_rail.cpp | 4 ++-- src/script/api/script_rail.hpp | 2 +- src/script/api/script_road.cpp | 4 ++-- src/script/api/script_road.hpp | 2 +- src/script/api/script_sign.cpp | 4 ++-- src/script/api/script_sign.hpp | 2 +- src/script/api/script_town.cpp | 4 ++-- src/script/api/script_town.hpp | 2 +- src/script/api/script_vehicle.cpp | 4 ++-- src/script/api/script_vehicle.hpp | 2 +- src/script/squirrel_helper.hpp | 15 +++++++++++++-- 39 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/script/api/script_basestation.cpp b/src/script/api/script_basestation.cpp index 408543ae8a..1863ea8554 100644 --- a/src/script/api/script_basestation.cpp +++ b/src/script/api/script_basestation.cpp @@ -26,9 +26,9 @@ return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE); } -/* static */ char *ScriptBaseStation::GetName(StationID station_id) +/* static */ std::optional ScriptBaseStation::GetName(StationID station_id) { - if (!IsValidBaseStation(station_id)) return nullptr; + if (!IsValidBaseStation(station_id)) return std::nullopt; ::SetDParam(0, station_id); return GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME); diff --git a/src/script/api/script_basestation.hpp b/src/script/api/script_basestation.hpp index 9f39368a30..52df57f78c 100644 --- a/src/script/api/script_basestation.hpp +++ b/src/script/api/script_basestation.hpp @@ -43,7 +43,7 @@ public: * @pre IsValidBaseStation(station_id). * @return The name of the station. */ - static char *GetName(StationID station_id); + static std::optional GetName(StationID station_id); /** * Set the name this basestation. diff --git a/src/script/api/script_bridge.cpp b/src/script/api/script_bridge.cpp index 939641ad94..d09c214e48 100644 --- a/src/script/api/script_bridge.cpp +++ b/src/script/api/script_bridge.cpp @@ -129,10 +129,10 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) return ScriptObject::Command::Do(tile); } -/* static */ char *ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type) +/* static */ std::optional ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type) { - EnforcePrecondition(nullptr, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER); - if (!IsValidBridge(bridge_id)) return nullptr; + EnforcePrecondition(std::nullopt, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER); + if (!IsValidBridge(bridge_id)) return std::nullopt; return GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_id)->transport_name[vehicle_type]); } diff --git a/src/script/api/script_bridge.hpp b/src/script/api/script_bridge.hpp index cce84f812d..d7dc0df043 100644 --- a/src/script/api/script_bridge.hpp +++ b/src/script/api/script_bridge.hpp @@ -69,7 +69,7 @@ public: * @pre vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER * @return The name the bridge has. */ - static char *GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type); + static std::optional GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type); /** * Get the maximum speed of a bridge. diff --git a/src/script/api/script_cargo.cpp b/src/script/api/script_cargo.cpp index b0377a3e0e..ba0aaf3799 100644 --- a/src/script/api/script_cargo.cpp +++ b/src/script/api/script_cargo.cpp @@ -28,26 +28,25 @@ return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END); } -/* static */ char *ScriptCargo::GetName(CargoID cargo_type) +/* static */ std::optional ScriptCargo::GetName(CargoID cargo_type) { - if (!IsValidCargo(cargo_type)) return nullptr; + if (!IsValidCargo(cargo_type)) return std::nullopt; ::SetDParam(0, 1ULL << cargo_type); return GetString(STR_JUST_CARGO_LIST); } -/* static */ char *ScriptCargo::GetCargoLabel(CargoID cargo_type) +/* static */ std::optional ScriptCargo::GetCargoLabel(CargoID cargo_type) { - if (!IsValidCargo(cargo_type)) return nullptr; + if (!IsValidCargo(cargo_type)) return std::nullopt; const CargoSpec *cargo = ::CargoSpec::Get(cargo_type); /* cargo->label is a uint32 packing a 4 character non-terminated string, * like "PASS", "COAL", "OIL_". New ones can be defined by NewGRFs */ - char *cargo_label = MallocT(sizeof(cargo->label) + 1); + std::string cargo_label; for (uint i = 0; i < sizeof(cargo->label); i++) { - cargo_label[i] = GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8); + cargo_label.push_back(GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8)); } - cargo_label[sizeof(cargo->label)] = '\0'; return cargo_label; } diff --git a/src/script/api/script_cargo.hpp b/src/script/api/script_cargo.hpp index c5b5c1b5f0..f44d53dbae 100644 --- a/src/script/api/script_cargo.hpp +++ b/src/script/api/script_cargo.hpp @@ -90,7 +90,7 @@ public: * @pre IsValidCargo(cargo_type). * @return The name of the cargo type. */ - static char *GetName(CargoID cargo_type); + static std::optional GetName(CargoID cargo_type); /** * Gets the string representation of the cargo label. @@ -107,7 +107,7 @@ public: * - In other words: Only use the cargo label, if you know more about the behaviour * of a specific cargo from a specific industry set, than the API methods can tell you. */ - static char *GetCargoLabel(CargoID cargo_type); + static std::optional GetCargoLabel(CargoID cargo_type); /** * Checks whether the give cargo is a freight or not. diff --git a/src/script/api/script_client.cpp b/src/script/api/script_client.cpp index ede1b925fe..87f90d65c8 100644 --- a/src/script/api/script_client.cpp +++ b/src/script/api/script_client.cpp @@ -32,11 +32,11 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client) return (FindClientInfo(client) == nullptr ? ScriptClient::CLIENT_INVALID : client); } -/* static */ char *ScriptClient::GetName(ScriptClient::ClientID client) +/* static */ std::optional ScriptClient::GetName(ScriptClient::ClientID client) { NetworkClientInfo *ci = FindClientInfo(client); - if (ci == nullptr) return nullptr; - return stredup(ci->client_name.c_str()); + if (ci == nullptr) return std::nullopt; + return ci->client_name; } /* static */ ScriptCompany::CompanyID ScriptClient::GetCompany(ScriptClient::ClientID client) diff --git a/src/script/api/script_client.hpp b/src/script/api/script_client.hpp index 7400e7247c..dabd956f00 100644 --- a/src/script/api/script_client.hpp +++ b/src/script/api/script_client.hpp @@ -45,7 +45,7 @@ public: * @pre ResolveClientID(client) != CLIENT_INVALID. * @return The name of the given client. */ - static char *GetName(ClientID client); + static std::optional GetName(ClientID client); /** * Get the company in which the given client is playing. diff --git a/src/script/api/script_company.cpp b/src/script/api/script_company.cpp index 9d1b452d7e..a50590c09b 100644 --- a/src/script/api/script_company.cpp +++ b/src/script/api/script_company.cpp @@ -57,10 +57,10 @@ return ScriptObject::Command::Do(text); } -/* static */ char *ScriptCompany::GetName(ScriptCompany::CompanyID company) +/* static */ std::optional ScriptCompany::GetName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); - if (company == COMPANY_INVALID) return nullptr; + if (company == COMPANY_INVALID) return std::nullopt; ::SetDParam(0, company); return GetString(STR_COMPANY_NAME); @@ -79,20 +79,13 @@ return ScriptObject::Command::Do(text); } -/* static */ char *ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company) +/* static */ std::optional ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); + if (company == COMPANY_INVALID) return std::nullopt; - static const int len = 64; - char *president_name = MallocT(len); - if (company != COMPANY_INVALID) { - ::SetDParam(0, company); - ::GetString(president_name, STR_PRESIDENT_NAME, &president_name[len - 1]); - } else { - *president_name = '\0'; - } - - return president_name; + ::SetDParam(0, company); + return GetString(STR_PRESIDENT_NAME); } /* static */ bool ScriptCompany::SetPresidentGender(Gender gender) diff --git a/src/script/api/script_company.hpp b/src/script/api/script_company.hpp index cfb6cabf94..2afb47a3ff 100644 --- a/src/script/api/script_company.hpp +++ b/src/script/api/script_company.hpp @@ -150,7 +150,7 @@ public: * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The name of the given company. */ - static char *GetName(CompanyID company); + static std::optional GetName(CompanyID company); /** * Set the name of your president. @@ -168,7 +168,7 @@ public: * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The name of the president of the given company. */ - static char *GetPresidentName(CompanyID company); + static std::optional GetPresidentName(CompanyID company); /** * Set the gender of the president of your company. diff --git a/src/script/api/script_engine.cpp b/src/script/api/script_engine.cpp index db16861212..d833a91a33 100644 --- a/src/script/api/script_engine.cpp +++ b/src/script/api/script_engine.cpp @@ -41,9 +41,9 @@ return e != nullptr && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany()); } -/* static */ char *ScriptEngine::GetName(EngineID engine_id) +/* static */ std::optional ScriptEngine::GetName(EngineID engine_id) { - if (!IsValidEngine(engine_id)) return nullptr; + if (!IsValidEngine(engine_id)) return std::nullopt; ::SetDParam(0, engine_id); return GetString(STR_ENGINE_NAME); diff --git a/src/script/api/script_engine.hpp b/src/script/api/script_engine.hpp index 73414c1b4c..2baed5bec3 100644 --- a/src/script/api/script_engine.hpp +++ b/src/script/api/script_engine.hpp @@ -44,7 +44,7 @@ public: * @pre IsValidEngine(engine_id). * @return The name the engine has. */ - static char *GetName(EngineID engine_id); + static std::optional GetName(EngineID engine_id); /** * Get the cargo-type of an engine. In case it can transport multiple cargoes, it diff --git a/src/script/api/script_error.cpp b/src/script/api/script_error.cpp index 318a6ff494..3d365c23bb 100644 --- a/src/script/api/script_error.cpp +++ b/src/script/api/script_error.cpp @@ -23,9 +23,9 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S return ScriptObject::GetLastError(); } -/* static */ char *ScriptError::GetLastErrorString() +/* static */ std::optional ScriptError::GetLastErrorString() { - return stredup((*error_map_string.find(ScriptError::GetLastError())).second); + return (*error_map_string.find(ScriptError::GetLastError())).second; } /* static */ ScriptErrorType ScriptError::StringToError(StringID internal_string_id) diff --git a/src/script/api/script_error.hpp b/src/script/api/script_error.hpp index e461a7d46d..601e99dd0f 100644 --- a/src/script/api/script_error.hpp +++ b/src/script/api/script_error.hpp @@ -193,7 +193,7 @@ public: * Get the last error in string format (for human readability). * @return An ErrorMessage enum item, as string. */ - static char *GetLastErrorString(); + static std::optional GetLastErrorString(); /** * Get the error based on the OpenTTD StringID. diff --git a/src/script/api/script_event_types.cpp b/src/script/api/script_event_types.cpp index 9eb01a3682..e90b85f0a9 100644 --- a/src/script/api/script_event_types.cpp +++ b/src/script/api/script_event_types.cpp @@ -28,9 +28,9 @@ bool ScriptEventEnginePreview::IsEngineValid() const return e != nullptr && e->IsEnabled(); } -char *ScriptEventEnginePreview::GetName() +std::optional ScriptEventEnginePreview::GetName() { - if (!this->IsEngineValid()) return nullptr; + if (!this->IsEngineValid()) return std::nullopt; ::SetDParam(0, this->engine); return GetString(STR_ENGINE_NAME); diff --git a/src/script/api/script_event_types.hpp b/src/script/api/script_event_types.hpp index 24e50ae4b0..43eff7dc1b 100644 --- a/src/script/api/script_event_types.hpp +++ b/src/script/api/script_event_types.hpp @@ -239,7 +239,7 @@ public: * Get the name of the offered engine. * @return The name the engine has. */ - char *GetName(); + std::optional GetName(); /** * Get the cargo-type of the offered engine. In case it can transport multiple cargoes, it diff --git a/src/script/api/script_group.cpp b/src/script/api/script_group.cpp index 1f83c55d0c..490da7564a 100644 --- a/src/script/api/script_group.cpp +++ b/src/script/api/script_group.cpp @@ -68,9 +68,9 @@ return ScriptObject::Command::Do(AlterGroupMode::Rename, group_id, 0, text); } -/* static */ char *ScriptGroup::GetName(GroupID group_id) +/* static */ std::optional ScriptGroup::GetName(GroupID group_id) { - if (!IsValidGroup(group_id)) return nullptr; + if (!IsValidGroup(group_id)) return std::nullopt; ::SetDParam(0, group_id); return GetString(STR_GROUP_NAME); diff --git a/src/script/api/script_group.hpp b/src/script/api/script_group.hpp index ba61be3fd4..9971525765 100644 --- a/src/script/api/script_group.hpp +++ b/src/script/api/script_group.hpp @@ -84,7 +84,7 @@ public: * @pre IsValidGroup(group_id). * @return The name the group has. */ - static char *GetName(GroupID group_id); + static std::optional GetName(GroupID group_id); /** * Set parent group of a group. diff --git a/src/script/api/script_industry.cpp b/src/script/api/script_industry.cpp index 1a9203b23e..5bc98251c1 100644 --- a/src/script/api/script_industry.cpp +++ b/src/script/api/script_industry.cpp @@ -42,9 +42,9 @@ return ::GetIndustryIndex(tile); } -/* static */ char *ScriptIndustry::GetName(IndustryID industry_id) +/* static */ std::optional ScriptIndustry::GetName(IndustryID industry_id) { - if (!IsValidIndustry(industry_id)) return nullptr; + if (!IsValidIndustry(industry_id)) return std::nullopt; ::SetDParam(0, industry_id); return GetString(STR_INDUSTRY_NAME); diff --git a/src/script/api/script_industry.hpp b/src/script/api/script_industry.hpp index d7fca868d0..e396da62cb 100644 --- a/src/script/api/script_industry.hpp +++ b/src/script/api/script_industry.hpp @@ -79,7 +79,7 @@ public: * @pre IsValidIndustry(industry_id). * @return The name of the industry. */ - static char *GetName(IndustryID industry_id); + static std::optional GetName(IndustryID industry_id); /** * Set the custom text of an industry, shown in the GUI. diff --git a/src/script/api/script_industrytype.cpp b/src/script/api/script_industrytype.cpp index 3d7073e40b..8d47e338cb 100644 --- a/src/script/api/script_industrytype.cpp +++ b/src/script/api/script_industrytype.cpp @@ -57,9 +57,9 @@ return ::GetIndustrySpec(industry_type)->GetConstructionCost(); } -/* static */ char *ScriptIndustryType::GetName(IndustryType industry_type) +/* static */ std::optional ScriptIndustryType::GetName(IndustryType industry_type) { - if (!IsValidIndustryType(industry_type)) return nullptr; + if (!IsValidIndustryType(industry_type)) return std::nullopt; return GetString(::GetIndustrySpec(industry_type)->name); } diff --git a/src/script/api/script_industrytype.hpp b/src/script/api/script_industrytype.hpp index a581e58444..dfa4586f02 100644 --- a/src/script/api/script_industrytype.hpp +++ b/src/script/api/script_industrytype.hpp @@ -39,7 +39,7 @@ public: * @pre IsValidIndustryType(industry_type). * @return The name of an industry. */ - static char *GetName(IndustryType industry_type); + static std::optional GetName(IndustryType industry_type); /** * Get a list of CargoID possible produced by this industry-type. diff --git a/src/script/api/script_newgrf.cpp b/src/script/api/script_newgrf.cpp index 10a0a966c3..884918c549 100644 --- a/src/script/api/script_newgrf.cpp +++ b/src/script/api/script_newgrf.cpp @@ -50,15 +50,15 @@ ScriptNewGRFList::ScriptNewGRFList() return 0; } -/* static */ char *ScriptNewGRF::GetName(SQInteger grfid) +/* static */ std::optional ScriptNewGRF::GetName(SQInteger grfid) { grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations. for (auto c = _grfconfig; c != nullptr; c = c->next) { if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) { - return ::stredup(c->GetName()); + return c->GetName(); } } - return nullptr; + return std::nullopt; } diff --git a/src/script/api/script_newgrf.hpp b/src/script/api/script_newgrf.hpp index c11202a112..7b9b2286c5 100644 --- a/src/script/api/script_newgrf.hpp +++ b/src/script/api/script_newgrf.hpp @@ -50,7 +50,7 @@ public: * @pre ScriptNewGRF::IsLoaded(grfid). * @return The name of the NewGRF or null if no name is defined. */ - static char *GetName(SQInteger grfid); + static std::optional GetName(SQInteger grfid); }; #endif /* SCRIPT_NEWGRF_HPP */ diff --git a/src/script/api/script_object.cpp b/src/script/api/script_object.cpp index b0692c2aa7..0f78464432 100644 --- a/src/script/api/script_object.cpp +++ b/src/script/api/script_object.cpp @@ -218,12 +218,9 @@ ScriptObject::ActiveInstance::~ActiveInstance() return GetStorage()->log_data; } -/* static */ char *ScriptObject::GetString(StringID string) +/* static */ std::string ScriptObject::GetString(StringID string) { - char buffer[64]; - ::GetString(buffer, string, lastof(buffer)); - ::StrMakeValidInPlace(buffer, lastof(buffer), SVS_NONE); - return ::stredup(buffer); + return ::StrMakeValid(::GetString(string)); } /* static */ void ScriptObject::SetCallbackVariable(int index, int value) diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 606bc7c584..f4b5694bcc 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -282,7 +282,7 @@ protected: /** * Get an allocated string with all control codes stripped off. */ - static char *GetString(StringID string); + static std::string GetString(StringID string); private: /* Helper functions for DoCommand. */ diff --git a/src/script/api/script_objecttype.cpp b/src/script/api/script_objecttype.cpp index 842bdac4b7..7e036a3e3d 100644 --- a/src/script/api/script_objecttype.cpp +++ b/src/script/api/script_objecttype.cpp @@ -23,9 +23,9 @@ return ObjectSpec::Get(object_type)->IsEverAvailable(); } -/* static */ char *ScriptObjectType::GetName(ObjectType object_type) +/* static */ std::optional ScriptObjectType::GetName(ObjectType object_type) { - EnforcePrecondition(nullptr, IsValidObjectType(object_type)); + EnforcePrecondition(std::nullopt, IsValidObjectType(object_type)); return GetString(ObjectSpec::Get(object_type)->name); } diff --git a/src/script/api/script_objecttype.hpp b/src/script/api/script_objecttype.hpp index c4b9949308..9a5c47278f 100644 --- a/src/script/api/script_objecttype.hpp +++ b/src/script/api/script_objecttype.hpp @@ -33,7 +33,7 @@ public: * @pre IsValidObjectType(object_type). * @return The name of an object. */ - static char *GetName(ObjectType object_type); + static std::optional GetName(ObjectType object_type); /** * Get the number of views for an object-type. diff --git a/src/script/api/script_rail.cpp b/src/script/api/script_rail.cpp index fbbb2038f9..5f97941ebd 100644 --- a/src/script/api/script_rail.cpp +++ b/src/script/api/script_rail.cpp @@ -24,9 +24,9 @@ #include "../../safeguards.h" -/* static */ char *ScriptRail::GetName(RailType rail_type) +/* static */ std::optional ScriptRail::GetName(RailType rail_type) { - if (!IsRailTypeAvailable(rail_type)) return nullptr; + if (!IsRailTypeAvailable(rail_type)) return std::nullopt; return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text); } diff --git a/src/script/api/script_rail.hpp b/src/script/api/script_rail.hpp index 83a141e554..31425721e6 100644 --- a/src/script/api/script_rail.hpp +++ b/src/script/api/script_rail.hpp @@ -101,7 +101,7 @@ public: * means that the name could be something like "Maglev construction" instead * of just "Maglev". */ - static char *GetName(RailType rail_type); + static std::optional GetName(RailType rail_type); /** * Checks whether the given tile is actually a tile with rail that can be diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 2326247753..8a44793029 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -25,9 +25,9 @@ return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK; } -/* static */ char *ScriptRoad::GetName(RoadType road_type) +/* static */ std::optional ScriptRoad::GetName(RoadType road_type) { - if (!IsRoadTypeAvailable(road_type)) return nullptr; + if (!IsRoadTypeAvailable(road_type)) return std::nullopt; return GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name); } diff --git a/src/script/api/script_road.hpp b/src/script/api/script_road.hpp index 78d2f1b77c..0f3968226a 100644 --- a/src/script/api/script_road.hpp +++ b/src/script/api/script_road.hpp @@ -90,7 +90,7 @@ public: * @pre IsRoadTypeAvailable(road_type). * @return The name the road type has. */ - static char *GetName(RoadType road_type); + static std::optional GetName(RoadType road_type); /** * Determines whether a busstop or a truckstop is needed to transport a certain cargo. diff --git a/src/script/api/script_sign.cpp b/src/script/api/script_sign.cpp index 01488b8953..59077aa55c 100644 --- a/src/script/api/script_sign.cpp +++ b/src/script/api/script_sign.cpp @@ -47,9 +47,9 @@ return ScriptObject::Command::Do(sign_id, text); } -/* static */ char *ScriptSign::GetName(SignID sign_id) +/* static */ std::optional ScriptSign::GetName(SignID sign_id) { - if (!IsValidSign(sign_id)) return nullptr; + if (!IsValidSign(sign_id)) return std::nullopt; ::SetDParam(0, sign_id); return GetString(STR_SIGN_NAME); diff --git a/src/script/api/script_sign.hpp b/src/script/api/script_sign.hpp index 06a17da92b..1569ad9932 100644 --- a/src/script/api/script_sign.hpp +++ b/src/script/api/script_sign.hpp @@ -55,7 +55,7 @@ public: * @pre IsValidSign(sign_id). * @return The name of the sign. */ - static char *GetName(SignID sign_id); + static std::optional GetName(SignID sign_id); /** * Get the owner of a sign. diff --git a/src/script/api/script_town.cpp b/src/script/api/script_town.cpp index c39b9e1185..b250fa8b65 100644 --- a/src/script/api/script_town.cpp +++ b/src/script/api/script_town.cpp @@ -32,9 +32,9 @@ return ::Town::IsValidID(town_id); } -/* static */ char *ScriptTown::GetName(TownID town_id) +/* static */ std::optional ScriptTown::GetName(TownID town_id) { - if (!IsValidTown(town_id)) return nullptr; + if (!IsValidTown(town_id)) return std::nullopt; ::SetDParam(0, town_id); return GetString(STR_TOWN_NAME); diff --git a/src/script/api/script_town.hpp b/src/script/api/script_town.hpp index bd2167f0f7..b23840024b 100644 --- a/src/script/api/script_town.hpp +++ b/src/script/api/script_town.hpp @@ -142,7 +142,7 @@ public: * @pre IsValidTown(town_id). * @return The name of the town. */ - static char *GetName(TownID town_id); + static std::optional GetName(TownID town_id); /** * Rename a town. diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index 144e5e3e29..1e06e4f5fb 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -299,9 +299,9 @@ return ::Vehicle::Get(vehicle_id)->unitnumber; } -/* static */ char *ScriptVehicle::GetName(VehicleID vehicle_id) +/* static */ std::optional ScriptVehicle::GetName(VehicleID vehicle_id) { - if (!IsPrimaryVehicle(vehicle_id)) return nullptr; + if (!IsPrimaryVehicle(vehicle_id)) return std::nullopt; ::SetDParam(0, vehicle_id); return GetString(STR_VEHICLE_NAME); diff --git a/src/script/api/script_vehicle.hpp b/src/script/api/script_vehicle.hpp index e76ffccec5..bd6d79ebcc 100644 --- a/src/script/api/script_vehicle.hpp +++ b/src/script/api/script_vehicle.hpp @@ -137,7 +137,7 @@ public: * @pre IsPrimaryVehicle(vehicle_id). * @return The name the vehicle has. */ - static char *GetName(VehicleID vehicle_id); + static std::optional GetName(VehicleID vehicle_id); /** * Get the owner of a vehicle. diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index ed220b8b40..c73402c26d 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -52,11 +52,22 @@ namespace SQConvert { template <> struct Return { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32)res.value); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } }; - template <> struct Return { static inline int Set(HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } }; - template <> struct Return { static inline int Set(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } }; + template <> struct Return { /* Do not use char *, use std::optional instead. */ }; + template <> struct Return { /* Do not use const char *, use std::optional instead. */ }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } }; + template <> struct Return> { + static inline int Set(HSQUIRRELVM vm, std::optional res) { + if (res.has_value()) { + sq_pushstring(vm, res.value(), -1); + } else { + sq_pushnull(vm); + } + return 1; + } + }; + /** * To get a param from squirrel, we use this helper class. It converts to the right format. * We use a class instead of a plain function to allow us to use partial template specializations. From ab51175db2c980fbc6b387fecad615e98a2faed0 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 09:44:35 +0200 Subject: [PATCH 37/58] Codechange: use std::string for script config --- src/ai/ai_instance.cpp | 2 +- src/crashlog.cpp | 4 ++-- src/framerate_gui.cpp | 2 +- src/game/game_instance.cpp | 2 +- src/script/script_gui.cpp | 2 +- src/script/script_info.cpp | 21 ++++++------------ src/script/script_info.hpp | 39 ++++++++++++++-------------------- src/script/script_instance.cpp | 4 ++-- src/script/script_instance.hpp | 2 +- src/script/script_scanner.cpp | 12 +++++------ src/script/squirrel.cpp | 13 +++++------- src/script/squirrel.hpp | 4 ++-- 12 files changed, 45 insertions(+), 62 deletions(-) diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 5f8ac9d164..03ba8666c5 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -70,7 +70,7 @@ void AIInstance::Died() if (info != nullptr) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); - if (info->GetURL() != nullptr) { + if (!info->GetURL().empty()) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 6ee4c83505..c4ab30a8a0 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -200,12 +200,12 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const if (c->ai_info == nullptr) { buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index); } else { - buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); + buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName().c_str(), c->ai_info->GetVersion()); } } if (Game::GetInfo() != nullptr) { - buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); + buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName().c_str(), Game::GetInfo()->GetVersion()); } buffer += seprintf(buffer, last, "\n"); diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index eaa8fbf772..db9dea477f 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -368,7 +368,7 @@ static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX] = { static const char * GetAIName(int ai_index) { if (!Company::IsValidAiID(ai_index)) return ""; - return Company::Get(ai_index)->ai_info->GetName(); + return Company::Get(ai_index)->ai_info->GetName().c_str(); } /** @hideinitializer */ diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp index 36c3b984c8..9d23588702 100644 --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -73,7 +73,7 @@ void GameInstance::Died() if (info != nullptr) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); - if (info->GetURL() != nullptr) { + if (!info->GetURL().empty()) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index dab4a28b18..09c7a0098b 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -153,7 +153,7 @@ struct ScriptListWindow : public Window { SetDParam(0, selected_info->GetVersion()); DrawString(tr, STR_AI_LIST_VERSION); tr.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal; - if (selected_info->GetURL() != nullptr) { + if (!selected_info->GetURL().empty()) { SetDParamStr(0, selected_info->GetURL()); DrawString(tr, STR_AI_LIST_URL); tr.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal; diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 8c2554a7ab..5e48acbcac 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -20,13 +20,6 @@ ScriptInfo::~ScriptInfo() { - free(this->author); - free(this->name); - free(this->short_name); - free(this->description); - free(this->date); - free(this->instance_name); - free(this->url); free(this->SQ_instance); } @@ -69,17 +62,17 @@ bool ScriptInfo::CheckMethod(const char *name) const info->tar_file = info->scanner->GetTarFile(); /* Cache the data the info file gives us. */ - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR; if (!info->engine->CallIntegerMethod(*info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR; /* The GetURL function is optional. */ if (info->engine->MethodExists(*info->SQ_instance, "GetURL")) { - if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(*info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR; } /* Check if we have settings */ diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp index 35b35622bb..afddbf5650 100644 --- a/src/script/script_info.hpp +++ b/src/script/script_info.hpp @@ -32,14 +32,7 @@ public: ScriptInfo() : engine(nullptr), SQ_instance(nullptr), - author(nullptr), - name(nullptr), - short_name(nullptr), - description(nullptr), - date(nullptr), - instance_name(nullptr), version(0), - url(nullptr), scanner(nullptr) {} ~ScriptInfo(); @@ -47,22 +40,22 @@ public: /** * Get the Author of the script. */ - const char *GetAuthor() const { return this->author; } + const std::string &GetAuthor() const { return this->author; } /** * Get the Name of the script. */ - const char *GetName() const { return this->name; } + const std::string &GetName() const { return this->name; } /** * Get the 4 character long short name of the script. */ - const char *GetShortName() const { return this->short_name; } + const std::string &GetShortName() const { return this->short_name; } /** * Get the description of the script. */ - const char *GetDescription() const { return this->description; } + const std::string &GetDescription() const { return this->description; } /** * Get the version of the script. @@ -72,27 +65,27 @@ public: /** * Get the last-modified date of the script. */ - const char *GetDate() const { return this->date; } + const std::string &GetDate() const { return this->date; } /** * Get the name of the instance of the script to create. */ - const char *GetInstanceName() const { return this->instance_name; } + const std::string &GetInstanceName() const { return this->instance_name; } /** * Get the website for this script. */ - const char *GetURL() const { return this->url; } + const std::string &GetURL() const { return this->url; } /** * Get the filename of the main.nut script. */ - const char *GetMainScript() const { return this->main_script.c_str(); } + const std::string &GetMainScript() const { return this->main_script; } /** * Get the filename of the tar the script is in. */ - std::string GetTarFile() const { return this->tar_file; } + const std::string &GetTarFile() const { return this->tar_file; } /** * Check if a given method exists. @@ -152,14 +145,14 @@ protected: private: std::string main_script; ///< The full path of the script. std::string tar_file; ///< If, which tar file the script was in. - const char *author; ///< Author of the script. - const char *name; ///< Full name of the script. - const char *short_name; ///< Short name (4 chars) which uniquely identifies the script. - const char *description; ///< Small description of the script. - const char *date; ///< The date the script was written at. - const char *instance_name; ///< Name of the main class in the script. + std::string author; ///< Author of the script. + std::string name; ///< Full name of the script. + std::string short_name; ///< Short name (4 chars) which uniquely identifies the script. + std::string description; ///< Small description of the script. + std::string date; ///< The date the script was written at. + std::string instance_name; ///< Name of the main class in the script. int version; ///< Version of the script. - const char *url; ///< URL of the script. + std::string url; ///< URL of the script. class ScriptScanner *scanner; ///< ScriptScanner object that was used to scan this script info. }; diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index b970aa7094..71365850f4 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -67,7 +67,7 @@ ScriptInstance::ScriptInstance(const char *APIName) : this->engine->SetPrintFunction(&PrintFunc); } -void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company) +void ScriptInstance::Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company) { ScriptObject::ActiveInstance active(this); @@ -80,7 +80,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na try { ScriptObject::SetAllowDoCommand(false); /* Load and execute the script for this script */ - if (strcmp(main_script, "%_dummy") == 0) { + if (main_script == "%_dummy") { this->LoadDummyScript(); } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) { if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started."); diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index c9acf4c80a..98132a6f6c 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -55,7 +55,7 @@ public: * @param instance_name The name of the instance out of the script to load. * @param company Which company this script is serving. */ - void Initialize(const char *main_script, const char *instance_name, CompanyID company); + void Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company); /** * Get the value of a setting of the current instance. diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index cb43fb0d0c..6192b4f00e 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -97,8 +97,8 @@ void ScriptScanner::RegisterScript(ScriptInfo *info) std::string script_name = fmt::format("{}.{}", script_original_name, info->GetVersion()); /* Check if GetShortName follows the rules */ - if (strlen(info->GetShortName()) != 4) { - Debug(script, 0, "The script '{}' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName()); + if (info->GetShortName().size() != 4) { + Debug(script, 0, "The script '{}' returned a string from GetShortName() which is not four characters. Unable to load the script.", info->GetName()); delete info; return; } @@ -107,9 +107,9 @@ void ScriptScanner::RegisterScript(ScriptInfo *info) /* This script was already registered */ #ifdef _WIN32 /* Windows doesn't care about the case */ - if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) { + if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript())) { #else - if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) { + if (this->info_list[script_name]->GetMainScript() == info->GetMainScript()) { #endif delete info; return; @@ -206,7 +206,7 @@ struct ScriptFileChecksumCreator : FileScanner { static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir) { uint32 id = 0; - const char *str = info->GetShortName(); + const char *str = info->GetShortName().c_str(); for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j); if (id != ci->unique_id) return false; @@ -251,7 +251,7 @@ bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum) const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum) { for (const auto &item : this->info_list) { - if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript(); + if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript().c_str(); } return nullptr; } diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 3c8a802cc8..0d0d2724ba 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -469,7 +469,7 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool return true; } -/* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name) +/* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const std::string &class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name) { Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); @@ -479,12 +479,9 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool sq_pushroottable(vm); if (prepend_API_name) { - size_t len = strlen(class_name) + strlen(engine->GetAPIName()) + 1; - char *class_name2 = MallocT(len); - seprintf(class_name2, class_name2 + len - 1, "%s%s", engine->GetAPIName(), class_name); - - sq_pushstring(vm, class_name2, -1); - free(class_name2); + std::string prepended_class_name = engine->GetAPIName(); + prepended_class_name += class_name; + sq_pushstring(vm, prepended_class_name, -1); } else { sq_pushstring(vm, class_name, -1); } @@ -520,7 +517,7 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool return true; } -bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance) +bool Squirrel::CreateClassInstance(const std::string &class_name, void *real_instance, HSQOBJECT *instance) { ScriptAllocatorScope alloc_scope(this); return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, nullptr); diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 34325c7a3d..22c3435617 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -179,12 +179,12 @@ public: * @param prepend_API_name Optional parameter; if true, the class_name is prefixed with the current API name. * @return False if creating failed. */ - static bool CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name = false); + static bool CreateClassInstanceVM(HSQUIRRELVM vm, const std::string &class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name = false); /** * Exactly the same as CreateClassInstanceVM, only callable without instance of Squirrel. */ - bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance); + bool CreateClassInstance(const std::string &class_name, void *real_instance, HSQOBJECT *instance); /** * Get the real-instance pointer. From b1b578f988619e94775017e62893b2c22da9c37a Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 09:47:54 +0200 Subject: [PATCH 38/58] Cleanup: stredup-ing string variant for calling scripts --- src/script/squirrel.cpp | 10 ---------- src/script/squirrel.hpp | 1 - 2 files changed, 11 deletions(-) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 0d0d2724ba..7e656d0a08 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -432,16 +432,6 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT return true; } -bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend) -{ - HSQOBJECT ret; - if (!this->CallMethod(instance, method_name, &ret, suspend)) return false; - if (ret._type != OT_STRING) return false; - *res = stredup(ObjectToString(&ret)); - StrMakeValidInPlace(const_cast(*res)); - return true; -} - bool Squirrel::CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend) { HSQOBJECT ret; diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 22c3435617..85b0bd1cf6 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -159,7 +159,6 @@ public: */ bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend); bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); } - bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend); bool CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend); bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend); bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend); From d9e93edc8b7b1c9856c9bfda9193c6a4373ab6f4 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 10:07:54 +0200 Subject: [PATCH 39/58] Codechange: replace 'const char *' script API parameters with std::string --- cmake/scripts/SquirrelExport.cmake | 2 +- src/ai/ai_instance.cpp | 2 +- src/ai/ai_instance.hpp | 2 +- src/game/game_instance.cpp | 2 +- src/game/game_instance.hpp | 2 +- src/script/api/script_controller.cpp | 6 +++--- src/script/api/script_controller.hpp | 4 ++-- src/script/api/script_gamesettings.cpp | 6 +++--- src/script/api/script_gamesettings.hpp | 6 +++--- src/script/api/script_text.cpp | 2 +- src/script/api/script_text.hpp | 2 +- src/script/script_instance.hpp | 2 +- src/script/squirrel_helper.hpp | 17 +---------------- 13 files changed, 20 insertions(+), 35 deletions(-) diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake index 76fbdd68ab..0e91501682 100644 --- a/cmake/scripts/SquirrelExport.cmake +++ b/cmake/scripts/SquirrelExport.cmake @@ -42,7 +42,7 @@ macro(dump_class_templates NAME) string(APPEND SQUIRREL_EXPORT "\n return Param::Get(vm, index, ptr);") string(APPEND SQUIRREL_EXPORT "\n }") string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") - string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index, ptr));") + string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index, ptr));") string(APPEND SQUIRREL_EXPORT "\n }") string(APPEND SQUIRREL_EXPORT "\n return nullptr;") string(APPEND SQUIRREL_EXPORT "\n }") diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 03ba8666c5..a5eda5c617 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -83,7 +83,7 @@ void AIInstance::LoadDummyScript() Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI"); } -int AIInstance::GetSetting(const char *name) +int AIInstance::GetSetting(const std::string &name) { return AIConfig::GetConfig(_current_company)->GetSetting(name); } diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp index 12b5159425..015f966ed5 100644 --- a/src/ai/ai_instance.hpp +++ b/src/ai/ai_instance.hpp @@ -23,7 +23,7 @@ public: */ void Initialize(class AIInfo *info); - int GetSetting(const char *name) override; + int GetSetting(const std::string &name) override; ScriptInfo *FindLibrary(const std::string &library, int version) override; private: diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp index 9d23588702..59d6e0d7d0 100644 --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -53,7 +53,7 @@ void GameInstance::RegisterAPI() if (!this->LoadCompatibilityScripts(this->versionAPI, GAME_DIR)) this->Died(); } -int GameInstance::GetSetting(const char *name) +int GameInstance::GetSetting(const std::string &name) { return GameConfig::GetConfig()->GetSetting(name); } diff --git a/src/game/game_instance.hpp b/src/game/game_instance.hpp index 4b5e1b0452..0a7a83abe1 100644 --- a/src/game/game_instance.hpp +++ b/src/game/game_instance.hpp @@ -23,7 +23,7 @@ public: */ void Initialize(class GameInfo *info); - int GetSetting(const char *name) override; + int GetSetting(const std::string &name) override; ScriptInfo *FindLibrary(const std::string &library, int version) override; private: diff --git a/src/script/api/script_controller.cpp b/src/script/api/script_controller.cpp index cd39319f0d..2ffbf46730 100644 --- a/src/script/api/script_controller.cpp +++ b/src/script/api/script_controller.cpp @@ -84,7 +84,7 @@ ScriptController::ScriptController(CompanyID company) : return ScriptObject::GetActiveInstance()->GetOpsTillSuspend(); } -/* static */ int ScriptController::GetSetting(const char *name) +/* static */ int ScriptController::GetSetting(const std::string &name) { return ScriptObject::GetActiveInstance()->GetSetting(name); } @@ -94,7 +94,7 @@ ScriptController::ScriptController(CompanyID company) : return _openttd_newgrf_version; } -/* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version) +/* static */ HSQOBJECT ScriptController::Import(const std::string &library, const std::string &class_name, int version) { ScriptController *controller = ScriptObject::GetActiveInstance()->GetController(); Squirrel *engine = ScriptObject::GetActiveInstance()->engine; @@ -152,7 +152,7 @@ ScriptController::ScriptController(CompanyID company) : sq_getstackobj(vm, -1, &obj); sq_pop(vm, 3); - if (StrEmpty(class_name)) return obj; + if (class_name.empty()) return obj; /* Now link the name the user wanted to our 'fake' class */ sq_pushobject(vm, parent); diff --git a/src/script/api/script_controller.hpp b/src/script/api/script_controller.hpp index f1e7cc9ea5..58419fafb3 100644 --- a/src/script/api/script_controller.hpp +++ b/src/script/api/script_controller.hpp @@ -125,7 +125,7 @@ public: * @param name The name of the setting. * @return the value for the setting, or -1 if the setting is not known. */ - static int GetSetting(const char *name); + static int GetSetting(const std::string &name); /** * Get the OpenTTD version of this executable. The version is formatted @@ -201,7 +201,7 @@ public: * @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name. * @note This command can be called from the global space, and does not need an instance. */ - static HSQOBJECT Import(const char *library, const char *class_name, int version); + static HSQOBJECT Import(const std::string &library, const std::string &class_name, int version); private: typedef std::map LoadedLibraryList; ///< The type for loaded libraries. diff --git a/src/script/api/script_gamesettings.cpp b/src/script/api/script_gamesettings.cpp index c8d99c36e6..2749bb6773 100644 --- a/src/script/api/script_gamesettings.cpp +++ b/src/script/api/script_gamesettings.cpp @@ -16,13 +16,13 @@ #include "../../safeguards.h" -/* static */ bool ScriptGameSettings::IsValid(const char *setting) +/* static */ bool ScriptGameSettings::IsValid(const std::string &setting) { const SettingDesc *sd = GetSettingFromName(setting); return sd != nullptr && sd->IsIntSetting(); } -/* static */ SQInteger ScriptGameSettings::GetValue(const char *setting) +/* static */ SQInteger ScriptGameSettings::GetValue(const std::string &setting) { if (!IsValid(setting)) return -1; @@ -31,7 +31,7 @@ return sd->AsIntSetting()->Read(&_settings_game); } -/* static */ bool ScriptGameSettings::SetValue(const char *setting, SQInteger value) +/* static */ bool ScriptGameSettings::SetValue(const std::string &setting, SQInteger value) { EnforceDeityOrCompanyModeValid(false); if (!IsValid(setting)) return false; diff --git a/src/script/api/script_gamesettings.hpp b/src/script/api/script_gamesettings.hpp index 83d023e70f..d4bbf609de 100644 --- a/src/script/api/script_gamesettings.hpp +++ b/src/script/api/script_gamesettings.hpp @@ -44,7 +44,7 @@ public: * @note Results achieved in the past offer no guarantee for the future. * @return True if and only if the setting is valid. */ - static bool IsValid(const char *setting); + static bool IsValid(const std::string &setting); /** * Gets the value of the game setting. @@ -57,7 +57,7 @@ public: * @note Results achieved in the past offer no guarantee for the future. * @return The value for the setting. */ - static SQInteger GetValue(const char *setting); + static SQInteger GetValue(const std::string &setting); /** * Sets the value of the game setting. @@ -69,7 +69,7 @@ public: * @note Results achieved in the past offer no guarantee for the future. * @api -ai */ - static bool SetValue(const char *setting, SQInteger value); + static bool SetValue(const std::string &setting, SQInteger value); /** * Checks whether the given vehicle-type is disabled for companies. diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 2445d2044f..b6f46e9f59 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -20,7 +20,7 @@ #include "../../safeguards.h" -RawText::RawText(const char *text) : text(text) +RawText::RawText(const std::string &text) : text(text) { } diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 597f2bdd74..8c8171de85 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -42,7 +42,7 @@ public: */ class RawText : public Text { public: - RawText(const char *text); + RawText(const std::string &text); const std::string GetEncodedText() override { return this->text; } private: diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 98132a6f6c..3666db38bd 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -62,7 +62,7 @@ public: * @param name The name of the setting. * @return the value for the setting, or -1 if the setting is not known. */ - virtual int GetSetting(const char *name) = 0; + virtual int GetSetting(const std::string &name) = 0; /** * Find a library. diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index c73402c26d..f323f9c8e2 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -84,24 +84,9 @@ namespace SQConvert { template <> struct Param { static inline TileIndex Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } }; template <> struct Param { static inline Money Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; template <> struct Param { static inline bool Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } }; + template <> struct Param { /* Do not use const char *, use std::string& instead. */ }; template <> struct Param { static inline void *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } }; - template <> struct Param { - static inline const char *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) - { - /* Convert what-ever there is as parameter to a string */ - sq_tostring(vm, index); - - const SQChar *tmp; - sq_getstring(vm, -1, &tmp); - char *tmp_str = stredup(tmp); - sq_poptop(vm); - ptr->push_back((void *)tmp_str); - StrMakeValidInPlace(tmp_str); - return tmp_str; - } - }; - template <> struct Param { static inline const std::string Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { From f9b5bc7ee6123153364c32ac0f02f3851e288d3a Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 10:24:31 +0200 Subject: [PATCH 40/58] Cleanup: the need for SQAutoFreePointers has gone --- cmake/scripts/SquirrelExport.cmake | 16 ++++----- src/script/api/script_road.cpp | 4 +-- src/script/api/script_road.hpp | 2 +- src/script/squirrel_helper.hpp | 56 +++++++++++------------------- 4 files changed, 31 insertions(+), 47 deletions(-) diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake index 0e91501682..e4096bc9de 100644 --- a/cmake/scripts/SquirrelExport.cmake +++ b/cmake/scripts/SquirrelExport.cmake @@ -28,21 +28,21 @@ endmacro() macro(dump_class_templates NAME) string(REGEX REPLACE "^Script" "" REALNAME ${NAME}) - string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") - string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") - string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") - string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") if("${NAME}" STREQUAL "ScriptEvent") string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };") elseif("${NAME}" STREQUAL "ScriptText") string(APPEND SQUIRREL_EXPORT "\n") string(APPEND SQUIRREL_EXPORT "\n template <> struct Param {") - string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {") + string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index) {") string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {") - string(APPEND SQUIRREL_EXPORT "\n return Param::Get(vm, index, ptr);") + string(APPEND SQUIRREL_EXPORT "\n return Param::Get(vm, index);") string(APPEND SQUIRREL_EXPORT "\n }") string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") - string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index, ptr));") + string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index));") string(APPEND SQUIRREL_EXPORT "\n }") string(APPEND SQUIRREL_EXPORT "\n return nullptr;") string(APPEND SQUIRREL_EXPORT "\n }") @@ -299,7 +299,7 @@ foreach(LINE IN LISTS SOURCE_LINES) endif() string(APPEND SQUIRREL_EXPORT "\n /* Allow enums to be used as Squirrel parameters */") foreach(ENUM IN LISTS ENUMS) - string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };") string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${ENUM}> { static inline int Set(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; } };") endforeach() endif() diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 8a44793029..8eeeb45dfe 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -379,7 +379,7 @@ static bool NormaliseTileOffset(int32 *tile) return false; } -/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> existing, TileIndex start_, TileIndex end_) +/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> &&existing, TileIndex start_, TileIndex end_) { ::Slope slope = (::Slope)slope_; int32 start = start_; @@ -420,7 +420,7 @@ static bool NormaliseTileOffset(int32 *tile) if (HasBit(rb, i)) existing.emplace_back(neighbours[i]); } - return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile); + return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), std::move(existing), start - tile, end - tile); } /** diff --git a/src/script/api/script_road.hpp b/src/script/api/script_road.hpp index 0f3968226a..4b5c15236f 100644 --- a/src/script/api/script_road.hpp +++ b/src/script/api/script_road.hpp @@ -246,7 +246,7 @@ public: * they are build or 2 when building the first part automatically * builds the second part. -1 means the preconditions are not met. */ - static SQInteger CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> existing, TileIndex start, TileIndex end); + static SQInteger CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> &&existing, TileIndex start, TileIndex end); /** * Lookup function for building road parts independent of whether the diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index f323f9c8e2..c20f76815f 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -23,19 +23,6 @@ template const char *GetClassName(); * The Squirrel convert routines */ namespace SQConvert { - /** - * Pointers assigned to this class will be free'd when this instance - * comes out of scope. Useful to make sure you can use stredup(), - * without leaking memory. - */ - struct SQAutoFreePointers : std::vector { - ~SQAutoFreePointers() - { - for (void * p : *this) free(p); - } - }; - - /** * To return a value to squirrel, we use this helper class. It converts to the right format. * We use a class instead of a plain function to allow us to use partial template specializations. @@ -74,21 +61,21 @@ namespace SQConvert { */ template struct Param; - template <> struct Param { static inline uint8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline uint16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline uint32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline int8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline int16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline int32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline int64 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline TileIndex Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } }; - template <> struct Param { static inline Money Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; - template <> struct Param { static inline bool Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } }; + template <> struct Param { static inline uint8 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint16 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint32 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int8 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int16 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int32 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int64 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline TileIndex Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } }; + template <> struct Param { static inline Money Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline bool Get(HSQUIRRELVM vm, int index) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } }; template <> struct Param { /* Do not use const char *, use std::string& instead. */ }; - template <> struct Param { static inline void *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline void *Get(HSQUIRRELVM vm, int index) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } }; template <> struct Param { - static inline const std::string Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) + static inline const std::string Get(HSQUIRRELVM vm, int index) { /* Convert what-ever there is as parameter to a string */ sq_tostring(vm, index); @@ -102,8 +89,8 @@ namespace SQConvert { }; template - struct Param> { - static inline Array Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) + struct Param &&> { + static inline Array Get(HSQUIRRELVM vm, int index) { /* Sanity check of the size. */ if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large"); @@ -116,7 +103,7 @@ namespace SQConvert { Array data; while (SQ_SUCCEEDED(sq_next(vm, -2))) { - data.emplace_back(Param::Get(vm, -1, ptr)); + data.emplace_back(Param::Get(vm, -1)); sq_pop(vm, 2); } sq_pop(vm, 2); @@ -146,15 +133,14 @@ namespace SQConvert { template static int SQCall(void *instance, Tretval(*func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - [[maybe_unused]] SQAutoFreePointers ptr; if constexpr (std::is_void_v) { (*func)( - Param::Get(vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i)... ); return 0; } else { Tretval ret = (*func)( - Param::Get(vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i)... ); return Return::Set(vm, ret); } @@ -180,15 +166,14 @@ namespace SQConvert { template static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - [[maybe_unused]] SQAutoFreePointers ptr; if constexpr (std::is_void_v) { (instance->*func)( - Param::Get(vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i)... ); return 0; } else { Tretval ret = (instance->*func)( - Param::Get(vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i)... ); return Return::Set(vm, ret); } @@ -197,9 +182,8 @@ namespace SQConvert { template static Tcls *SQConstruct(Tcls *, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - [[maybe_unused]] SQAutoFreePointers ptr; Tcls *inst = new Tcls( - Param::Get(vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i)... ); return inst; From 62fda0f5057d263e38a9eea4e77afec13b5125ee Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 6 May 2023 14:19:41 +0200 Subject: [PATCH 41/58] Codechange: remove manual allocation/free for SQ_instance --- src/ai/ai_info.cpp | 14 +++++++------- src/game/game_info.cpp | 12 ++++++------ src/script/script_info.cpp | 34 ++++++++++++++-------------------- src/script/script_info.hpp | 4 +--- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index fac36129a3..c2757427f5 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -69,20 +69,20 @@ template <> const char *GetClassName() { return "AIInfo" SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; - if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { - if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) { + if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; } else { info->min_loadable_version = info->GetVersion(); } /* When there is an UseAsRandomAI function, call it. */ - if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) { - if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "UseAsRandomAI")) { + if (!info->engine->CallBoolMethod(info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR; } else { info->use_as_random = true; } /* Try to get the API version the AI is written for. */ - if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) { - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) { + if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; @@ -149,7 +149,7 @@ bool AIInfo::CanLoadFromVersion(int version) const } /* Cache the category */ - if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { + if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp index 88347c5157..db3b53e259 100644 --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -60,20 +60,20 @@ template <> const char *GetClassName() { return "GSInf SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; - if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { - if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) { + if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; } else { info->min_loadable_version = info->GetVersion(); } /* When there is an IsSelectable function, call it. */ - if (info->engine->MethodExists(*info->SQ_instance, "IsDeveloperOnly")) { - if (!info->engine->CallBoolMethod(*info->SQ_instance, "IsDeveloperOnly", &info->is_developer_only, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "IsDeveloperOnly")) { + if (!info->engine->CallBoolMethod(info->SQ_instance, "IsDeveloperOnly", &info->is_developer_only, MAX_GET_OPS)) return SQ_ERROR; } else { info->is_developer_only = false; } /* Try to get the API version the AI is written for. */ if (!info->CheckMethod("GetAPIVersion")) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; @@ -119,7 +119,7 @@ bool GameInfo::CanLoadFromVersion(int version) const } /* Cache the category */ - if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { + if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 5e48acbcac..ec3c668fa6 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -18,14 +18,9 @@ #include "../safeguards.h" -ScriptInfo::~ScriptInfo() -{ - free(this->SQ_instance); -} - bool ScriptInfo::CheckMethod(const char *name) const { - if (!this->engine->MethodExists(*this->SQ_instance, name)) { + if (!this->engine->MethodExists(this->SQ_instance, name)) { this->engine->ThrowError(fmt::format("your info.nut/library.nut doesn't have the method '{}'", name)); return false; } @@ -35,10 +30,9 @@ bool ScriptInfo::CheckMethod(const char *name) const /* static */ SQInteger ScriptInfo::Constructor(HSQUIRRELVM vm, ScriptInfo *info) { /* Set some basic info from the parent */ - info->SQ_instance = MallocT(1); - Squirrel::GetInstance(vm, info->SQ_instance, 2); + Squirrel::GetInstance(vm, &info->SQ_instance, 2); /* Make sure the instance stays alive over time */ - sq_addref(vm, info->SQ_instance); + sq_addref(vm, &info->SQ_instance); info->scanner = (ScriptScanner *)Squirrel::GetGlobalPointer(vm); info->engine = info->scanner->GetEngine(); @@ -62,21 +56,21 @@ bool ScriptInfo::CheckMethod(const char *name) const info->tar_file = info->scanner->GetTarFile(); /* Cache the data the info file gives us. */ - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallIntegerMethod(*info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR; - if (!info->engine->CallStringMethod(*info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallIntegerMethod(info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR; + if (!info->engine->CallStringMethod(info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR; /* The GetURL function is optional. */ - if (info->engine->MethodExists(*info->SQ_instance, "GetURL")) { - if (!info->engine->CallStringMethod(*info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR; + if (info->engine->MethodExists(info->SQ_instance, "GetURL")) { + if (!info->engine->CallStringMethod(info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR; } /* Check if we have settings */ - if (info->engine->MethodExists(*info->SQ_instance, "GetSettings")) { + if (info->engine->MethodExists(info->SQ_instance, "GetSettings")) { if (!info->GetSettings()) return SQ_ERROR; } @@ -85,7 +79,7 @@ bool ScriptInfo::CheckMethod(const char *name) const bool ScriptInfo::GetSettings() { - return this->engine->CallMethod(*this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS); + return this->engine->CallMethod(this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS); } SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp index afddbf5650..90a04d13d8 100644 --- a/src/script/script_info.hpp +++ b/src/script/script_info.hpp @@ -31,11 +31,9 @@ class ScriptInfo : public SimpleCountedObject { public: ScriptInfo() : engine(nullptr), - SQ_instance(nullptr), version(0), scanner(nullptr) {} - ~ScriptInfo(); /** * Get the Author of the script. @@ -139,7 +137,7 @@ public: protected: class Squirrel *engine; ///< Engine used to register for Squirrel. - HSQOBJECT *SQ_instance; ///< The Squirrel instance created for this info. + HSQOBJECT SQ_instance; ///< The Squirrel instance created for this info. ScriptConfigItemList config_list; ///< List of settings from this Script. private: From 021c45c4f641676e06401001c9c9cb9b6c6a74cc Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 2 May 2023 20:45:04 +0200 Subject: [PATCH 42/58] Add: [CMake] JSON library (nlohmann) --- .github/workflows/ci-build.yml | 15 ++-- .github/workflows/release-linux.yml | 3 +- .github/workflows/release-macos.yml | 4 +- .github/workflows/release-windows.yml | 3 +- CMakeLists.txt | 2 + COMPILING.md | 6 +- os/emscripten/Dockerfile | 3 + os/emscripten/README.md | 11 +-- os/emscripten/cmake/FindLibLZMA.cmake | 4 +- os/emscripten/cmake/Findnlohmann_json.cmake | 20 +++++ os/emscripten/emsdk-nlohmann-json.patch | 93 +++++++++++++++++++++ 11 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 os/emscripten/cmake/Findnlohmann_json.cmake create mode 100644 os/emscripten/emsdk-nlohmann-json.patch diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 4b3fafd8f0..6ddb2e5901 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -76,20 +76,20 @@ jobs: - name: Clang compiler: clang cxxcompiler: clang++ - libraries: libsdl2-dev + libraries: libsdl2-dev nlohmann-json3-dev - name: GCC - SDL2 compiler: gcc cxxcompiler: g++ - libraries: libsdl2-dev + libraries: libsdl2-dev nlohmann-json3-dev - name: GCC - SDL1.2 compiler: gcc cxxcompiler: g++ - libraries: libsdl1.2-dev + libraries: libsdl1.2-dev nlohmann-json3-dev - name: GCC - Dedicated compiler: gcc cxxcompiler: g++ extra-cmake-parameters: -DOPTION_DEDICATED=ON -DCMAKE_CXX_FLAGS_INIT="-DRANDOM_DEBUG" -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON - # Compile without SDL / SDL2, as that should compile fine too. + # Compile without SDL / SDL2 / nlohmann-json, as that should compile fine too. name: Linux (${{ matrix.name }}) @@ -197,7 +197,7 @@ jobs: uses: actions/cache@v3 with: path: /usr/local/share/vcpkg/installed - key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified + key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified restore-keys: | ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }} @@ -208,6 +208,7 @@ jobs: liblzma \ libpng \ lzo \ + nlohmann-json \ zlib \ # EOF @@ -280,7 +281,7 @@ jobs: uses: actions/cache@v3 with: path: vcpkg/installed - key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified + key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified restore-keys: | ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }} @@ -291,6 +292,7 @@ jobs: liblzma \ libpng \ lzo \ + nlohmann-json \ zlib \ # EOF @@ -377,6 +379,7 @@ jobs: mingw-w64-${{ matrix.arch }}-libpng mingw-w64-${{ matrix.arch }}-lld mingw-w64-${{ matrix.arch }}-ninja + mingw-w64-${{ matrix.arch }}-nlohmann-json - name: Install OpenGFX shell: bash diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 0f8ba153c6..78080af80b 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -27,7 +27,7 @@ jobs: uses: actions/cache@v3 with: path: /vcpkg/installed - key: ubuntu-20.04-vcpkg-release-0 # Increase the number whenever dependencies are modified + key: ubuntu-20.04-vcpkg-release-1 # Increase the number whenever dependencies are modified restore-keys: | ubuntu-20.04-vcpkg-release @@ -79,6 +79,7 @@ jobs: liblzma \ libpng \ lzo \ + nlohmann-json \ sdl2 \ zlib \ # EOF diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml index 1240fae0ab..0654e99424 100644 --- a/.github/workflows/release-macos.yml +++ b/.github/workflows/release-macos.yml @@ -40,7 +40,7 @@ jobs: uses: actions/cache@v3 with: path: /usr/local/share/vcpkg/installed - key: ${{ steps.key.outputs.image }}-vcpkg-release-0 # Increase the number whenever dependencies are modified + key: ${{ steps.key.outputs.image }}-vcpkg-release-1 # Increase the number whenever dependencies are modified restore-keys: | ${{ steps.key.outputs.image }}-vcpkg-release ${{ steps.key.outputs.image }}-vcpkg-x64 @@ -56,6 +56,8 @@ jobs: libpng:arm64-osx \ lzo:x64-osx \ lzo:arm64-osx \ + nlohmann-json:x64-osx \ + nlohmann-json:arm64-osx \ zlib:x64-osx \ zlib:arm64-osx \ # EOF diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 347cb03386..2f934139e1 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -53,7 +53,7 @@ jobs: uses: actions/cache@v3 with: path: vcpkg/installed - key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified + key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified restore-keys: | ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }} @@ -64,6 +64,7 @@ jobs: liblzma \ libpng \ lzo \ + nlohmann-json \ zlib \ # EOF diff --git a/CMakeLists.txt b/CMakeLists.txt index 27b7b0e7d2..ca0b261d85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ find_package(ZLIB) find_package(LibLZMA) find_package(LZO) find_package(PNG) +find_package(nlohmann_json) if(WIN32 OR EMSCRIPTEN) # Windows uses WinHttp for HTTP requests. @@ -293,6 +294,7 @@ link_package(PNG TARGET PNG::PNG ENCOURAGED) link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED) link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED) link_package(LZO) +link_package(nlohmann_json ENCOURAGED) if(NOT WIN32 AND NOT EMSCRIPTEN) link_package(CURL ENCOURAGED) diff --git a/COMPILING.md b/COMPILING.md index 551afe39cb..be1bad79ab 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -4,6 +4,7 @@ OpenTTD makes use of the following external libraries: +- (encouraged) nlohmann-json: JSON handling - (encouraged) zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads, heightmaps - (encouraged) liblzma: (de)compressing of savegames (1.1.0 and later) @@ -52,13 +53,14 @@ the `static` versions, and OpenTTD currently needs the following dependencies: - liblzma - libpng - lzo +- nlohmann-json - zlib To install both the x64 (64bit) and x86 (32bit) variants (though only one is necessary), you can use: ```ps -.\vcpkg install liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static zlib:x64-windows-static -.\vcpkg install liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static zlib:x86-windows-static +.\vcpkg install liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static nlohmann-json:x64-windows-static zlib:x64-windows-static +.\vcpkg install liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static nlohmann-json:x86-windows-static zlib:x86-windows-static ``` You can open the folder (as a CMake project). CMake will be detected, and you can compile from there. diff --git a/os/emscripten/Dockerfile b/os/emscripten/Dockerfile index e92858df87..4ded7fe57c 100644 --- a/os/emscripten/Dockerfile +++ b/os/emscripten/Dockerfile @@ -2,3 +2,6 @@ FROM emscripten/emsdk:3.1.37 COPY emsdk-liblzma.patch / RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-liblzma.patch + +COPY emsdk-nlohmann-json.patch / +RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-nlohmann-json.patch diff --git a/os/emscripten/README.md b/os/emscripten/README.md index cf8e3ed692..c16eea2416 100644 --- a/os/emscripten/README.md +++ b/os/emscripten/README.md @@ -4,10 +4,11 @@ Please use docker with the supplied `Dockerfile` to build for emscripten. It takes care of a few things: - Use a version of emscripten we know works - Patch in LibLZMA support (as this is not supported by upstream) +- Patch in nlohmann-json support (as this is not supported by upstream) First, build the docker image by navigating in the folder this `README.md` is in, and executing: ``` - docker build -t emsdk-lzma . + docker build -t emsdk-openttd . ``` Next, navigate back to the root folder of this project. @@ -15,15 +16,15 @@ Next, navigate back to the root folder of this project. Now we build the host tools first: ``` mkdir build-host - docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma cmake .. -DOPTION_TOOLS_ONLY=ON - docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma make -j$(nproc) tools + docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-openttd cmake .. -DOPTION_TOOLS_ONLY=ON + docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-openttd make -j$(nproc) tools ``` Finally, we build the actual game: ``` mkdir build - docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emcmake cmake .. -DHOST_BINARY_DIR=../build-host -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_ASSERTS=OFF - docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emmake make -j$(nproc) + docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-openttd emcmake cmake .. -DHOST_BINARY_DIR=../build-host -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_ASSERTS=OFF + docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-openttd emmake make -j$(nproc) ``` In the `build` folder you will now see `openttd.html`. diff --git a/os/emscripten/cmake/FindLibLZMA.cmake b/os/emscripten/cmake/FindLibLZMA.cmake index e8a024c4ee..cd6b44ad3d 100644 --- a/os/emscripten/cmake/FindLibLZMA.cmake +++ b/os/emscripten/cmake/FindLibLZMA.cmake @@ -1,5 +1,5 @@ -# LibLZMA is a recent addition to the emscripten SDK, so it is possible -# someone hasn't updated their SDK yet. Test out if the SDK supports LibLZMA. +# LibLZMA is a custom addition to the emscripten SDK, so it is possible +# someone patched their SDK. Test out if the SDK supports LibLZMA. include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_FLAGS "-sUSE_LIBLZMA=1") diff --git a/os/emscripten/cmake/Findnlohmann_json.cmake b/os/emscripten/cmake/Findnlohmann_json.cmake new file mode 100644 index 0000000000..6ff84544da --- /dev/null +++ b/os/emscripten/cmake/Findnlohmann_json.cmake @@ -0,0 +1,20 @@ +# nlohmann-json is a custom addition to the emscripten SDK, so it is possible +# someone patched their SDK. Test out if the SDK supports nlohmann-json. +include(CheckCXXSourceCompiles) +set(CMAKE_REQUIRED_FLAGS "-sUSE_NLOHMANN_JSON=1") + +check_cxx_source_compiles(" + #include + int main() { return 0; }" + NLOHMANN_JSON_FOUND +) + +if (NLOHMANN_JSON_FOUND) + add_library(nlohmann_json INTERFACE IMPORTED) + set_target_properties(nlohmann_json PROPERTIES + INTERFACE_COMPILE_OPTIONS "-sUSE_NLOHMANN_JSON=1" + INTERFACE_LINK_LIBRARIES "-sUSE_NLOHMANN_JSON=1" + ) +else() + message(WARNING "You are using an emscripten SDK without nlohmann-json support. Please apply 'emsdk-nlohmann_json.patch' to your local emsdk installation.") +endif() diff --git a/os/emscripten/emsdk-nlohmann-json.patch b/os/emscripten/emsdk-nlohmann-json.patch new file mode 100644 index 0000000000..37d052a2a7 --- /dev/null +++ b/os/emscripten/emsdk-nlohmann-json.patch @@ -0,0 +1,93 @@ +From 0edcedbea375e59f41df10acaee0c483d245751f Mon Sep 17 00:00:00 2001 +From: Patric Stout +Date: Tue, 2 May 2023 21:48:08 +0200 +Subject: [PATCH] Add nlohmmann-json port + +--- + src/settings.js | 4 ++++ + tools/ports/nlohmann_json.py | 46 ++++++++++++++++++++++++++++++++++++ + tools/settings.py | 1 + + 3 files changed, 51 insertions(+) + create mode 100644 tools/ports/nlohmann_json.py + +diff --git a/src/settings.js b/src/settings.js +index f93140d..39f4366 100644 +--- a/src/settings.js ++++ b/src/settings.js +@@ -1483,6 +1483,10 @@ var USE_MPG123 = false; + // [compile+link] + var USE_FREETYPE = false; + ++// 1 = use nlohmann-json from emscripten-ports ++// [compile+link] ++var USE_NLOHMANN_JSON = false; ++ + // Specify the SDL_mixer version that is being linked against. + // Doesn't *have* to match USE_SDL, but a good idea. + // [compile+link] +diff --git a/tools/ports/nlohmann_json.py b/tools/ports/nlohmann_json.py +new file mode 100644 +index 0000000..9e44297 +--- /dev/null ++++ b/tools/ports/nlohmann_json.py +@@ -0,0 +1,46 @@ ++# Copyright 2023 The Emscripten Authors. All rights reserved. ++# Emscripten is available under two separate licenses, the MIT license and the ++# University of Illinois/NCSA Open Source License. Both these licenses can be ++# found in the LICENSE file. ++ ++import os ++ ++TAG = '3.11.2' ++HASH = '99d9e6d588cabe8913a37437f86acb5d4b8b98bce12423e633c11c13b61e6c7f92ef8f9a4e991baa590329ee2b5c09ca9db9894bee1e54bdd68e8d09d83cc245' ++ ++ ++def needed(settings): ++ return settings.USE_NLOHMANN_JSON ++ ++ ++def get(ports, settings, shared): ++ ports.fetch_project('nlohmann_json', ++ f'https://github.com/nlohmann/json/releases/download/v{TAG}/include.zip', ++ sha512hash=HASH) ++ ++ def create(final): ++ source_path = os.path.join(ports.get_dir(), 'nlohmann_json') ++ source_path_include = os.path.join(source_path, 'include', 'nlohmann') ++ ports.install_header_dir(source_path_include, 'nlohmann') ++ ++ # write out a dummy cpp file, to create an empty library ++ # this is needed as emscripten ports expect this, even if it is not used ++ dummy_file = os.path.join(source_path, 'dummy.cpp') ++ shared.safe_ensure_dirs(os.path.dirname(dummy_file)) ++ ports.write_file(dummy_file, 'static void dummy() {}') ++ ++ ports.build_port(source_path, final, 'nlohmann_json', srcs=['dummy.cpp']) ++ ++ return [shared.cache.get_lib('libnlohmann_json.a', create, what='port')] ++ ++ ++def clear(ports, settings, shared): ++ shared.cache.erase_lib('libnlohmann_json.a') ++ ++ ++def process_args(ports): ++ return [] ++ ++ ++def show(): ++ return 'nlohmann-json' +diff --git a/tools/settings.py b/tools/settings.py +index 10d6ca0..8536092 100644 +--- a/tools/settings.py ++++ b/tools/settings.py +@@ -47,6 +47,7 @@ PORTS_SETTINGS = { + 'USE_MPG123', + 'USE_GIFLIB', + 'USE_FREETYPE', ++ 'USE_NLOHMANN_JSON', + 'SDL2_MIXER_FORMATS', + 'SDL2_IMAGE_FORMATS', + 'USE_SQLITE3', +-- +2.34.1 From 7634553d2211a0ed3393315065ef210a9d020499 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 25 Apr 2023 19:43:45 +0200 Subject: [PATCH 43/58] Feature: opt-in survey when exiting a game On first start-up, the game will ask if you want to participate in our automated survey. You have to opt-in, and can easily opt-out (via the Options) at any time. When opt-in, whenever you exit a game, a JSON blob will be send to the survey server hosted by OpenTTD. This JSON blob contains information that gives a global picture of the game just played: - What settings were used - How many humans vs AIs - How long the game has been played - Basic information about the OS / CPU All this information is kept very generic, so there is no chance we send private information to our survey server. Nothing in the JSON blob could identify you as a person; it mostly tells about the game played. At any time you can see what the JSON blob includes, by pressing the "Preview Survey Results" button in-game. --- .github/workflows/codeql.yml | 2 + .github/workflows/release-linux.yml | 6 + .github/workflows/release-macos.yml | 7 + .github/workflows/release-source.yml | 16 + .github/workflows/release-windows.yml | 6 + .github/workflows/release.yml | 7 + cmake/Options.cmake | 12 + src/ai/ai_gui.cpp | 4 +- src/crashlog.cpp | 5 + src/game/game_gui.cpp | 4 +- src/gfx.cpp | 1 + src/intro_gui.cpp | 6 +- src/lang/english.txt | 18 +- src/misc.cpp | 36 ++ src/network/CMakeLists.txt | 2 + src/network/core/config.cpp | 10 + src/network/core/config.h | 4 + src/network/core/http.h | 2 + src/network/core/http_curl.cpp | 17 +- src/network/core/http_winhttp.cpp | 7 +- src/network/network.cpp | 21 +- src/network/network_content_gui.cpp | 4 +- src/network/network_gui.cpp | 118 ++++++ src/network/network_gui.h | 3 +- src/network/network_survey.cpp | 397 ++++++++++++++++++ src/network/network_survey.h | 54 +++ src/newgrf_gui.cpp | 4 +- src/openttd.cpp | 22 + src/openttd.h | 3 + src/os/macosx/CMakeLists.txt | 1 + src/os/macosx/macos.h | 2 + src/os/macosx/macos.mm | 5 + src/os/macosx/survey_osx.cpp | 38 ++ src/os/unix/CMakeLists.txt | 1 + src/os/unix/survey_unix.cpp | 38 ++ src/os/windows/CMakeLists.txt | 1 + src/os/windows/survey_win.cpp | 37 ++ src/saveload/afterload.cpp | 4 + src/saveload/misc_sl.cpp | 2 + src/saveload/saveload.h | 1 + src/settings_gui.cpp | 52 ++- src/settings_type.h | 12 +- .../settings/network_private_settings.ini | 11 + src/textfile_gui.cpp | 17 +- src/textfile_gui.h | 3 + src/textfile_type.h | 12 +- src/widget.cpp | 2 +- src/widgets/ai_widget.h | 2 +- src/widgets/game_widget.h | 2 +- src/widgets/network_content_widget.h | 2 +- src/widgets/network_widget.h | 10 + src/widgets/newgrf_widget.h | 2 +- src/widgets/settings_widget.h | 10 +- src/window_type.h | 6 + 54 files changed, 1018 insertions(+), 53 deletions(-) create mode 100644 src/network/network_survey.cpp create mode 100644 src/network/network_survey.h create mode 100644 src/os/macosx/survey_osx.cpp create mode 100644 src/os/unix/survey_unix.cpp create mode 100644 src/os/windows/survey_win.cpp diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 912223e500..fbab30ba54 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,10 +37,12 @@ jobs: liballegro4-dev \ libcurl4-openssl-dev \ libfontconfig-dev \ + libharfbuzz-dev \ libicu-dev \ liblzma-dev \ liblzo2-dev \ libsdl2-dev \ + nlohmann-json3-dev \ zlib1g-dev \ # EOF echo "::endgroup::" diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 78080af80b..30c2a04ee4 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -2,6 +2,11 @@ name: Release (Linux) on: workflow_call: + inputs: + survey_key: + required: false + type: string + default: "" jobs: linux: @@ -119,6 +124,7 @@ jobs: cmake ${GITHUB_WORKSPACE} \ -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \ -DOPTION_PACKAGE_DEPENDENCIES=ON \ # EOF echo "::endgroup::" diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml index 0654e99424..596692eaab 100644 --- a/.github/workflows/release-macos.yml +++ b/.github/workflows/release-macos.yml @@ -2,6 +2,11 @@ name: Release (MacOS) on: workflow_call: + inputs: + survey_key: + required: false + type: string + default: "" jobs: macos: @@ -104,6 +109,7 @@ jobs: -DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \ -DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \ # EOF echo "::endgroup::" @@ -124,6 +130,7 @@ jobs: -DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \ -DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \ -DCPACK_BUNDLE_APPLE_CERT_APP=${{ secrets.APPLE_DEVELOPER_CERTIFICATE_ID }} \ "-DCPACK_BUNDLE_APPLE_CODESIGN_PARAMETER=--deep -f --options runtime" \ -DAPPLE_UNIVERSAL_PACKAGE=1 \ diff --git a/.github/workflows/release-source.yml b/.github/workflows/release-source.yml index 2213efed25..9cf9c779a1 100644 --- a/.github/workflows/release-source.yml +++ b/.github/workflows/release-source.yml @@ -11,6 +11,8 @@ on: value: ${{ jobs.source.outputs.trigger_type }} folder: value: ${{ jobs.source.outputs.folder }} + survey_key: + value: ${{ jobs.source.outputs.survey_key }} jobs: source: @@ -23,6 +25,7 @@ jobs: is_tag: ${{ steps.metadata.outputs.is_tag }} trigger_type: ${{ steps.metadata.outputs.trigger_type }} folder: ${{ steps.metadata.outputs.folder }} + survey_key: ${{ steps.survey_key.outputs.survey_key }} steps: - name: Checkout (Release) @@ -146,6 +149,19 @@ jobs: FOLDER_NIGHTLIES: openttd-nightlies FOLDER_BRANCHES: openttd-branches + - name: Generate survey key + id: survey_key + run: | + PAYLOAD='{"version":"${{ steps.metadata.outputs.version }}","type":"${{ vars.SURVEY_TYPE }}"}' + + echo "${{ secrets.SURVEY_SIGNING_KEY }}" > survey_signing_key.pem + SIGNATURE=$(echo -n "${PAYLOAD}" | openssl dgst -sha256 -sign survey_signing_key.pem | base64 -w0) + rm -f survey_signing_key.pem + + SURVEY_KEY=$(curl -f -s -X POST -d "${PAYLOAD}" -H "Content-Type: application/json" -H "X-Signature: ${SIGNATURE}" https://survey-participate.openttd.org/create-survey-key/${{ vars.SURVEY_TYPE }}) + + echo "survey_key=${SURVEY_KEY}" >> $GITHUB_OUTPUT + - name: Remove VCS information run: | rm -rf .git diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 2f934139e1..c55a4f8d4a 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -3,6 +3,10 @@ name: Release (Windows) on: workflow_call: inputs: + survey_key: + required: false + type: string + default: "" is_tag: required: true type: string @@ -129,6 +133,7 @@ jobs: -DOPTION_USE_NSIS=ON \ -DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \ -DWINDOWS_CERTIFICATE_COMMON_NAME="${WINDOWS_CERTIFICATE_COMMON_NAME}" \ # EOF echo "::endgroup::" @@ -153,6 +158,7 @@ jobs: -DCMAKE_TOOLCHAIN_FILE="c:\vcpkg\scripts\buildsystems\vcpkg.cmake" \ -DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \ -DWINDOWS_CERTIFICATE_COMMON_NAME="${WINDOWS_CERTIFICATE_COMMON_NAME}" \ # EOF echo "::endgroup::" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc0225153f..5aeccfb39d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,6 +38,9 @@ jobs: uses: ./.github/workflows/release-linux.yml secrets: inherit + with: + survey_key: ${{ needs.source.outputs.survey_key }} + macos: name: MacOS needs: source @@ -45,6 +48,9 @@ jobs: uses: ./.github/workflows/release-macos.yml secrets: inherit + with: + survey_key: ${{ needs.source.outputs.survey_key }} + windows: name: Windows needs: source @@ -54,6 +60,7 @@ jobs: with: is_tag: ${{ needs.source.outputs.is_tag }} + survey_key: ${{ needs.source.outputs.survey_key }} windows-store: name: Windows Store diff --git a/cmake/Options.cmake b/cmake/Options.cmake index 42d1127906..371b03d841 100644 --- a/cmake/Options.cmake +++ b/cmake/Options.cmake @@ -71,6 +71,8 @@ function(set_options) if (OPTION_DOCS_ONLY) set(OPTION_TOOLS_ONLY ON PARENT_SCOPE) endif() + + option(OPTION_SURVEY_KEY "Survey-key to use for the opt-in survey (empty if you have none)" "") endfunction() # Show the values of the generic options. @@ -84,6 +86,12 @@ function(show_options) message(STATUS "Option Use assert - ${OPTION_USE_ASSERTS}") message(STATUS "Option Use threads - ${OPTION_USE_THREADS}") message(STATUS "Option Use NSIS - ${OPTION_USE_NSIS}") + + if(OPTION_SURVEY_KEY) + message(STATUS "Option Survey Key - USED") + else() + message(STATUS "Option Survey Key - NOT USED") + endif() endfunction() # Add the definitions for the options that are selected. @@ -104,4 +112,8 @@ function(add_definitions_based_on_options) else() add_definitions(-DNDEBUG) endif() + + if(OPTION_SURVEY_KEY) + add_definitions(-DSURVEY_KEY="${OPTION_SURVEY_KEY}") + endif() endfunction() diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index ac2daee27d..a74586246d 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -183,7 +183,7 @@ struct AIConfigWindow : public Window { void OnClick(Point pt, int widget, int click_count) override { - if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) { + if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_CONTENT_END) { if (this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot) == nullptr) return; ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot); @@ -284,7 +284,7 @@ struct AIConfigWindow : public Window { this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1))); this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot + 1))); - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || !AIConfig::GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot).has_value()); } } diff --git a/src/crashlog.cpp b/src/crashlog.cpp index c4ab30a8a0..e3be578da1 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -23,6 +23,7 @@ #include "screenshot.h" #include "gfx_func.h" #include "network/network.h" +#include "network/network_survey.h" #include "language.h" #include "fontcache.h" #include "news_gui.h" @@ -511,6 +512,10 @@ bool CrashLog::MakeCrashLog() const printf("Writing crash screenshot failed.\n\n"); } + if (_game_mode == GM_NORMAL) { + _survey.Transmit(NetworkSurveyHandler::Reason::CRASH, true); + } + return ret; } diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp index e4c24e7f25..8b0c1a3333 100644 --- a/src/game/game_gui.cpp +++ b/src/game/game_gui.cpp @@ -240,7 +240,7 @@ struct GSConfigWindow : public Window { void OnClick(Point pt, int widget, int click_count) override { - if (widget >= WID_GSC_TEXTFILE && widget < WID_GSC_TEXTFILE + TFT_END) { + if (widget >= WID_GSC_TEXTFILE && widget < WID_GSC_TEXTFILE + TFT_CONTENT_END) { if (GameConfig::GetConfig() == nullptr) return; ShowScriptTextfileWindow((TextfileType)(widget - WID_GSC_TEXTFILE), (CompanyID)OWNER_DEITY); @@ -404,7 +404,7 @@ struct GSConfigWindow : public Window { this->SetWidgetDisabledState(WID_GSC_CHANGE, (_game_mode == GM_NORMAL) || !IsEditable()); - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_GSC_TEXTFILE + tft, !GameConfig::GetConfig()->GetTextfile(tft, (CompanyID)OWNER_DEITY).has_value()); } this->RebuildVisibleSettings(); diff --git a/src/gfx.cpp b/src/gfx.cpp index 53ca6ab349..f9d587e258 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -47,6 +47,7 @@ bool _screen_disable_anim = false; ///< Disable palette animation (important f std::atomic _exit_game; GameMode _game_mode; SwitchMode _switch_mode; ///< The next mainloop command. +std::chrono::steady_clock::time_point _switch_mode_time; ///< The time when the switch mode was requested. PauseMode _pause_mode; Palette _cur_palette; diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 1d84732bf7..f445b0d62d 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -17,6 +17,7 @@ #include "genworld.h" #include "network/network_gui.h" #include "network/network_content.h" +#include "network/network_survey.h" #include "landscape_type.h" #include "landscape.h" #include "strings_func.h" @@ -504,7 +505,10 @@ void ShowSelectGameWindow() static void AskExitGameCallback(Window *w, bool confirmed) { - if (confirmed) _exit_game = true; + if (confirmed) { + _survey.Transmit(NetworkSurveyHandler::Reason::EXIT, true); + _exit_game = true; + } } void AskExitGame() diff --git a/src/lang/english.txt b/src/lang/english.txt index 18c9909454..f5ed779815 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1041,6 +1041,14 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Participate in automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}When enabled, OpenTTD will transmit a survey when leaving a game +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}About survey and privacy +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}This opens a browser with more information about the automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Preview survey result +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Show the survey result of the current running game + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphics STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Display refresh rate @@ -2402,6 +2410,13 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Yes, this once STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Yes, don't ask again +STR_NETWORK_ASK_SURVEY_CAPTION :Participate in automated survey? +STR_NETWORK_ASK_SURVEY_TEXT :Would you like to participate in the automated survey?{}OpenTTD will transmit a survey when leaving a game.{}You can change this at any time under "Game Options". +STR_NETWORK_ASK_SURVEY_PREVIEW :Preview survey result +STR_NETWORK_ASK_SURVEY_LINK :About survey and privacy +STR_NETWORK_ASK_SURVEY_NO :No +STR_NETWORK_ASK_SURVEY_YES :Yes + STR_NETWORK_SPECTATORS :Spectators # Network set password @@ -4654,10 +4669,11 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the STR_TEXTFILE_VIEW_README :{BLACK}View readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {RAW_STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {RAW_STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licence of {RAW_STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Preview of survey result # Vehicle loading indicators diff --git a/src/misc.cpp b/src/misc.cpp index b8748d7b3b..5169a6dfc5 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -31,9 +31,11 @@ #include "town_kdtree.h" #include "viewport_kdtree.h" #include "newgrf_profiling.h" +#include "3rdparty/md5/md5.h" #include "safeguards.h" +std::string _savegame_id; ///< Unique ID of the current savegame. extern TileIndex _cur_tileloop_tile; extern void MakeNewgameSettingsLive(); @@ -56,6 +58,40 @@ void InitializeCheats(); void InitializeNPF(); void InitializeOldNames(); +/** + * Generate an unique ID. + * + * It isn't as much of an unique ID as we would like, but our random generator + * can only produce 32bit random numbers. + * That is why we combine InteractiveRandom with the current (steady) clock. + * The first to add a bit of randomness, the second to ensure you can't get + * the same unique ID when you run it twice from the same state at different + * times. + * + * This makes it unlikely that two users generate the same ID for different + * subjects. But as this is not an UUID, so it can't be ruled out either. + */ +std::string GenerateUid(std::string_view subject) +{ + auto current_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + std::string coding_string = fmt::format("{}{}{}", InteractiveRandom(), current_time, subject); + + Md5 checksum; + uint8 digest[16]; + checksum.Append(coding_string.c_str(), coding_string.length()); + checksum.Finish(digest); + + return MD5SumToString(digest); +} + +/** + * Generate an unique savegame ID. + */ +void GenerateSavegameId() +{ + _savegame_id = GenerateUid("OpenTTD Savegame ID"); +} + void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings) { /* Make sure there isn't any window that can influence anything diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 07a4dfd97b..5b97de5cd2 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -28,6 +28,8 @@ add_files( network_server.h network_stun.cpp network_stun.h + network_survey.cpp + network_survey.h network_turn.cpp network_turn.h network_type.h diff --git a/src/network/core/config.cpp b/src/network/core/config.cpp index 21de508ccf..8451ecac58 100644 --- a/src/network/core/config.cpp +++ b/src/network/core/config.cpp @@ -66,3 +66,13 @@ const char *NetworkContentMirrorUriString() { return GetEnv("OTTD_CONTENT_MIRROR_URI", "https://binaries.openttd.org/bananas"); } + +/** + * Get the URI string for the survey from the environment variable OTTD_SURVEY_URI, + * or when it has not been set a hard coded URI of the production server. + * @return The survey's URI string. + */ +const char *NetworkSurveyUriString() +{ + return GetEnv("OTTD_SURVEY_URI", "https://survey-participate.openttd.org/"); +} diff --git a/src/network/core/config.h b/src/network/core/config.h index 7571f05a54..023b96a044 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -16,6 +16,7 @@ const char *NetworkCoordinatorConnectionString(); const char *NetworkStunConnectionString(); const char *NetworkContentServerConnectionString(); const char *NetworkContentMirrorUriString(); +const char *NetworkSurveyUriString(); static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP) static const uint16 NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP) @@ -26,6 +27,8 @@ static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The d static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet + +static const std::string NETWORK_SURVEY_DETAILS_LINK = "https://survey.openttd.org/participate"; ///< Link with more details & privacy statement of the survey. /* * Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future * to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8. @@ -46,6 +49,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe static const byte NETWORK_GAME_ADMIN_VERSION = 3; ///< What version of the admin network do we use? static const byte NETWORK_GAME_INFO_VERSION = 6; ///< What version of game-info do we use? static const byte NETWORK_COORDINATOR_VERSION = 6; ///< What version of game-coordinator-protocol do we use? +static const byte NETWORK_SURVEY_VERSION = 1; ///< What version of the survey do we use? static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' diff --git a/src/network/core/http.h b/src/network/core/http.h index 78b5be87af..d851faf9c6 100644 --- a/src/network/core/http.h +++ b/src/network/core/http.h @@ -14,6 +14,8 @@ #include "tcp.h" +constexpr int HTTP_429_TOO_MANY_REQUESTS = 429; + /** Callback for when the HTTP handler has something to tell us. */ struct HTTPCallback { /** diff --git a/src/network/core/http_curl.cpp b/src/network/core/http_curl.cpp index 4b8337b411..f8f591eaed 100644 --- a/src/network/core/http_curl.cpp +++ b/src/network/core/http_curl.cpp @@ -116,6 +116,7 @@ void HttpThread() /* Reset to default settings. */ curl_easy_reset(curl); + curl_slist *headers = nullptr; if (_debug_net_level >= 5) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); @@ -146,8 +147,16 @@ void HttpThread() /* Prepare POST body and URI. */ if (!request->data.empty()) { + /* When the payload starts with a '{', it is a JSON payload. */ + if (StrStartsWith(request->data, "{")) { + headers = curl_slist_append(headers, "Content-Type: application/json"); + } else { + headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); + } + curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->data.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); } curl_easy_setopt(curl, CURLOPT_URL, request->uri.c_str()); @@ -174,11 +183,17 @@ void HttpThread() /* Perform the request. */ CURLcode res = curl_easy_perform(curl); + curl_slist_free_all(headers); + if (res == CURLE_OK) { Debug(net, 1, "HTTP request succeeded"); request->callback->OnReceiveData(nullptr, 0); } else { - Debug(net, (request->callback->IsCancelled() || _http_thread_exit) ? 1 : 0, "HTTP request failed: {}", curl_easy_strerror(res)); + long status_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code); + + /* No need to be verbose about rate limiting. */ + Debug(net, (request->callback->IsCancelled() || _http_thread_exit || status_code == HTTP_429_TOO_MANY_REQUESTS) ? 1 : 0, "HTTP request failed: status_code: {}, error: {}", status_code, curl_easy_strerror(res)); request->callback->OnFailure(); } } diff --git a/src/network/core/http_winhttp.cpp b/src/network/core/http_winhttp.cpp index 9fc28d62cb..0d4744a808 100644 --- a/src/network/core/http_winhttp.cpp +++ b/src/network/core/http_winhttp.cpp @@ -131,7 +131,8 @@ void NetworkHTTPRequest::WinHttpCallback(DWORD code, void *info, DWORD length) /* If there is any error, we simply abort the request. */ if (status_code >= 400) { - Debug(net, 0, "HTTP request failed: status-code {}", status_code); + /* No need to be verbose about rate limiting. */ + Debug(net, status_code == HTTP_429_TOO_MANY_REQUESTS ? 1 : 0, "HTTP request failed: status-code {}", status_code); this->finished = true; this->callback->OnFailure(); return; @@ -242,7 +243,9 @@ void NetworkHTTPRequest::Connect() if (data.empty()) { WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast(this)); } else { - WinHttpSendRequest(this->request, L"Content-Type: application/x-www-form-urlencoded\r\n", -1, const_cast(data.c_str()), static_cast(data.size()), static_cast(data.size()), reinterpret_cast(this)); + /* When the payload starts with a '{', it is a JSON payload. */ + LPCWSTR content_type = StrStartsWith(data, "{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n"; + WinHttpSendRequest(this->request, content_type, -1, const_cast(data.c_str()), static_cast(data.size()), static_cast(data.size()), reinterpret_cast(this)); } } diff --git a/src/network/network.cpp b/src/network/network.cpp index 4b0ef622d3..b12b5b440c 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -85,6 +85,8 @@ static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS /** The amount of clients connected */ byte _network_clients_connected = 0; +extern std::string GenerateUid(std::string_view subject); + /** * Return whether there is any client connected or trying to connect at all. * @return whether we have any client activity @@ -1204,24 +1206,7 @@ void NetworkGameLoop() static void NetworkGenerateServerId() { - Md5 checksum; - uint8 digest[16]; - char hex_output[16 * 2 + 1]; - char coding_string[NETWORK_NAME_LENGTH]; - int di; - - seprintf(coding_string, lastof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID"); - - /* Generate the MD5 hash */ - checksum.Append((const uint8*)coding_string, strlen(coding_string)); - checksum.Finish(digest); - - for (di = 0; di < 16; ++di) { - seprintf(hex_output + di * 2, lastof(hex_output), "%02x", digest[di]); - } - - /* _settings_client.network.network_id is our id */ - _settings_client.network.network_id = hex_output; + _settings_client.network.network_id = GenerateUid("OpenTTD Server ID"); } class TCPNetworkDebugConnecter : TCPConnecter { diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 33950e43dc..ff049d2d58 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -790,7 +790,7 @@ public: void OnClick(Point pt, int widget, int click_count) override { - if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) { + if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_CONTENT_END) { if (this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE) return; ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected); @@ -997,7 +997,7 @@ public: this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all); this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade); this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || this->selected->url.empty()); - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || !this->selected->GetTextfile(tft).has_value()); } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 2771d0c074..6353b899d2 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -18,6 +18,7 @@ #include "network_content.h" #include "network_server.h" #include "network_coordinator.h" +#include "network_survey.h" #include "../gui.h" #include "network_udp.h" #include "../window_func.h" @@ -38,6 +39,7 @@ #include "../timer/timer.h" #include "../timer/timer_window.h" #include "../timer/timer_game_calendar.h" +#include "../textfile_gui.h" #include "../widgets/network_widget.h" @@ -2515,3 +2517,119 @@ void ShowNetworkAskRelay(const std::string &server_connection_string, const std: Window *parent = GetMainWindow(); new NetworkAskRelayWindow(&_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token); } + +/** + * Window used for asking if the user wants to participate in the automated survey. + */ +struct NetworkAskSurveyWindow : public Window { + NetworkAskSurveyWindow(WindowDesc *desc, Window *parent) : + Window(desc) + { + this->parent = parent; + this->InitNested(0); + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + if (widget == WID_NAS_TEXT) { + *size = GetStringBoundingBox(STR_NETWORK_ASK_SURVEY_TEXT); + size->width += WidgetDimensions::scaled.frametext.Horizontal(); + size->height += WidgetDimensions::scaled.frametext.Vertical(); + } + } + + void DrawWidget(const Rect &r, int widget) const override + { + if (widget == WID_NAS_TEXT) { + DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_NETWORK_ASK_SURVEY_TEXT, TC_BLACK, SA_CENTER); + } + } + + void FindWindowPlacementAndResize(int def_width, int def_height) override + { + /* Position query window over the calling window, ensuring it's within screen bounds. */ + this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width); + this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height); + this->SetDirty(); + } + + void OnClick(Point pt, int widget, int click_count) override + { + switch (widget) { + case WID_NAS_PREVIEW: + ShowSurveyResultTextfileWindow(); + break; + + case WID_NAS_LINK: + OpenBrowser(NETWORK_SURVEY_DETAILS_LINK.c_str()); + break; + + case WID_NAS_NO: + _settings_client.network.participate_survey = PS_NO; + this->Close(); + break; + + case WID_NAS_YES: + _settings_client.network.participate_survey = PS_YES; + this->Close(); + break; + } + } +}; + +static const NWidgetPart _nested_network_ask_survey_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_NAS_CAPTION), SetDataTip(STR_NETWORK_ASK_SURVEY_CAPTION, STR_NULL), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(0, 4, 8), + NWidget(WWT_TEXT, COLOUR_GREY, WID_NAS_TEXT), SetAlignment(SA_HOR_CENTER), SetFill(1, 1), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 15, 10), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_PREVIEW), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_PREVIEW, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NAS_LINK), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_LINK, STR_NULL), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 15, 10), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_NO, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NAS_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_NETWORK_ASK_SURVEY_YES, STR_NULL), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _network_ask_survey_desc( + WDP_CENTER, nullptr, 0, 0, + WC_NETWORK_ASK_SURVEY, WC_NONE, + WDF_MODAL, + _nested_network_ask_survey_widgets, lengthof(_nested_network_ask_survey_widgets) +); + +/** + * Show a modal confirmation window with "no" / "preview" / "yes" buttons. + */ +void ShowNetworkAskSurvey() +{ + /* If we can't send a survey, don't ask the question. */ + if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) return; + + CloseWindowByClass(WC_NETWORK_ASK_SURVEY); + + Window *parent = GetMainWindow(); + new NetworkAskSurveyWindow(&_network_ask_survey_desc, parent); +} + +/** Window for displaying the textfile of a survey result. */ +struct SurveyResultTextfileWindow : public TextfileWindow { + const GRFConfig *grf_config; ///< View the textfile of this GRFConfig. + + SurveyResultTextfileWindow(TextfileType file_type) : TextfileWindow(file_type) + { + auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true); + this->LoadText(result); + this->InvalidateData(); + } +}; + +void ShowSurveyResultTextfileWindow() +{ + CloseWindowById(WC_TEXTFILE, TFT_SURVEY_RESULT); + new SurveyResultTextfileWindow(TFT_SURVEY_RESULT); +} diff --git a/src/network/network_gui.h b/src/network/network_gui.h index 24cdbf7e76..4cd6ef4f19 100644 --- a/src/network/network_gui.h +++ b/src/network/network_gui.h @@ -24,7 +24,8 @@ void ShowNetworkGameWindow(); void ShowClientList(); void ShowNetworkCompanyPasswordWindow(Window *parent); void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token); - +void ShowNetworkAskSurvey(); +void ShowSurveyResultTextfileWindow(); /** Company information stored at the client side */ struct NetworkCompanyInfo : NetworkCompanyStats { diff --git a/src/network/network_survey.cpp b/src/network/network_survey.cpp new file mode 100644 index 0000000000..aa9aa84f11 --- /dev/null +++ b/src/network/network_survey.cpp @@ -0,0 +1,397 @@ +/* + * 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 network_survey.cpp Opt-in survey part of the network protocol. */ + +#include "../stdafx.h" +#include "network_survey.h" +#include "settings_table.h" +#include "network.h" +#include "../debug.h" +#include "../rev.h" +#include "../settings_type.h" +#include "../timer/timer_game_tick.h" + +#include "../currency.h" +#include "../fontcache.h" +#include "../language.h" + +#include "../ai/ai_info.hpp" +#include "../game/game.hpp" +#include "../game/game_info.hpp" + +#include "../music/music_driver.hpp" +#include "../sound/sound_driver.hpp" +#include "../video/video_driver.hpp" + +#include "../base_media_base.h" +#include "../blitter/factory.hpp" + +#ifdef WITH_NLOHMANN_JSON +#include +#endif /* WITH_NLOHMANN_JSON */ + +#include "../safeguards.h" + +extern std::string _savegame_id; + +NetworkSurveyHandler _survey = {}; + +#ifdef WITH_NLOHMANN_JSON + +NLOHMANN_JSON_SERIALIZE_ENUM(NetworkSurveyHandler::Reason, { + {NetworkSurveyHandler::Reason::PREVIEW, "preview"}, + {NetworkSurveyHandler::Reason::LEAVE, "leave"}, + {NetworkSurveyHandler::Reason::EXIT, "exit"}, + {NetworkSurveyHandler::Reason::CRASH, "crash"}, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(GRFStatus, { + {GRFStatus::GCS_UNKNOWN, "unknown"}, + {GRFStatus::GCS_DISABLED, "disabled"}, + {GRFStatus::GCS_NOT_FOUND, "not found"}, + {GRFStatus::GCS_INITIALISED, "initialised"}, + {GRFStatus::GCS_ACTIVATED, "activated"}, +}) + +static const std::string _vehicle_type_to_string[] = { + "train", + "roadveh", + "ship", + "aircraft", +}; + +/* Defined in one of the os/ survey files. */ +extern void SurveyOS(nlohmann::json &json); + +/** + * List of all the generic setting tables. + * + * There are a few tables that are special and not processed like the rest: + * - _currency_settings + * - _misc_settings + * - _company_settings + * - _win32_settings + * As such, they are not part of this list. + */ +static auto &GenericSettingTables() +{ + static const SettingTable _generic_setting_tables[] = { + _difficulty_settings, + _economy_settings, + _game_settings, + _gui_settings, + _linkgraph_settings, + _locale_settings, + _multimedia_settings, + _network_settings, + _news_display_settings, + _pathfinding_settings, + _script_settings, + _world_settings, + }; + return _generic_setting_tables; +} + +/** + * Convert a settings table to JSON. + * + * @param survey The JSON object. + * @param table The settings table to convert. + * @param object The object to get the settings from. + */ +static void SurveySettingsTable(nlohmann::json &survey, const SettingTable &table, void *object) +{ + char buf[512]; + for (auto &desc : table) { + const SettingDesc *sd = GetSettingDesc(desc); + /* Skip any old settings we no longer save/load. */ + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + + auto name = sd->GetName(); + sd->FormatValue(buf, lastof(buf), object); + + survey[name] = buf; + } +} + +/** + * Convert settings to JSON. + * + * @param survey The JSON object. + */ +static void SurveySettings(nlohmann::json &survey) +{ + SurveySettingsTable(survey, _misc_settings, nullptr); +#if defined(_WIN32) && !defined(DEDICATED) + SurveySettingsTable(survey, _win32_settings, nullptr); +#endif + for (auto &table : GenericSettingTables()) { + SurveySettingsTable(survey, table, &_settings_game); + } + SurveySettingsTable(survey, _currency_settings, &_custom_currency); + SurveySettingsTable(survey, _company_settings, &_settings_client.company); +} + +/** + * Convert generic OpenTTD information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyOpenTTD(nlohmann::json &survey) +{ + survey["version"] = std::string(_openttd_revision); + survey["newgrf_version"] = _openttd_newgrf_version; + survey["build_date"] = std::string(_openttd_build_date); + survey["bits"] = +#ifdef POINTER_IS_64BIT + 64 +#else + 32 +#endif + ; + survey["endian"] = +#if (TTD_ENDIAN == TTD_LITTLE_ENDIAN) + "little" +#else + "big" +#endif + ; + survey["dedicated_build"] = +#ifdef DEDICATED + "yes" +#else + "no" +#endif + ; +} + +/** + * Convert generic game information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyConfiguration(nlohmann::json &survey) +{ + survey["network"] = _networking ? (_network_server ? "server" : "client") : "no"; + if (_current_language != nullptr) { + std::string_view language_basename(_current_language->file); + auto e = language_basename.rfind(PATHSEPCHAR); + if (e != std::string::npos) { + language_basename = language_basename.substr(e + 1); + } + + survey["language"]["filename"] = language_basename; + survey["language"]["name"] = _current_language->name; + survey["language"]["isocode"] = _current_language->isocode; + } + if (BlitterFactory::GetCurrentBlitter() != nullptr) { + survey["blitter"] = BlitterFactory::GetCurrentBlitter()->GetName(); + } + if (MusicDriver::GetInstance() != nullptr) { + survey["music_driver"] = MusicDriver::GetInstance()->GetName(); + } + if (SoundDriver::GetInstance() != nullptr) { + survey["sound_driver"] = SoundDriver::GetInstance()->GetName(); + } + if (VideoDriver::GetInstance() != nullptr) { + survey["video_driver"] = VideoDriver::GetInstance()->GetName(); + survey["video_info"] = VideoDriver::GetInstance()->GetInfoString(); + } + if (BaseGraphics::GetUsedSet() != nullptr) { + survey["graphics_set"] = fmt::format("{}.{}", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); + } + if (BaseMusic::GetUsedSet() != nullptr) { + survey["music_set"] = fmt::format("{}.{}", BaseMusic::GetUsedSet()->name, BaseMusic::GetUsedSet()->version); + } + if (BaseSounds::GetUsedSet() != nullptr) { + survey["sound_set"] = fmt::format("{}.{}", BaseSounds::GetUsedSet()->name, BaseSounds::GetUsedSet()->version); + } +} + +/** + * Convert font information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyFont(nlohmann::json &survey) +{ + survey["small"] = FontCache::Get(FS_SMALL)->GetFontName(); + survey["medium"] = FontCache::Get(FS_NORMAL)->GetFontName(); + survey["large"] = FontCache::Get(FS_LARGE)->GetFontName(); + survey["mono"] = FontCache::Get(FS_MONO)->GetFontName(); +} + +/** + * Convert company information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyCompanies(nlohmann::json &survey) +{ + for (const Company *c : Company::Iterate()) { + auto &company = survey[std::to_string(c->index)]; + if (c->ai_info == nullptr) { + company["type"] = "human"; + } else { + company["type"] = "ai"; + company["script"] = fmt::format("{}.{}", c->ai_info->GetName(), c->ai_info->GetVersion()); + } + + for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { + uint amount = c->group_all[type].num_vehicle; + company["vehicles"][_vehicle_type_to_string[type]] = amount; + } + + company["infrastructure"]["road"] = c->infrastructure.GetRoadTotal(); + company["infrastructure"]["tram"] = c->infrastructure.GetTramTotal(); + company["infrastructure"]["rail"] = c->infrastructure.GetRailTotal(); + company["infrastructure"]["signal"] = c->infrastructure.signal; + company["infrastructure"]["water"] = c->infrastructure.water; + company["infrastructure"]["station"] = c->infrastructure.station; + company["infrastructure"]["airport"] = c->infrastructure.airport; + } +} + +/** + * Convert GRF information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyGrfs(nlohmann::json &survey) +{ + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + auto grfid = fmt::format("{:08x}", BSWAP32(c->ident.grfid)); + auto &grf = survey[grfid]; + + grf["md5sum"] = MD5SumToString(c->ident.md5sum); + grf["status"] = c->status; + + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_UNSET) grf["palette"] = "unset"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_DOS) grf["palette"] = "dos"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_WINDOWS) grf["palette"] = "windows"; + if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_ANY) grf["palette"] = "any"; + + if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_UNSET) grf["blitter"] = "unset"; + if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_32BPP) grf["blitter"] = "32bpp"; + + grf["is_static"] = HasBit(c->flags, GCF_STATIC); + + std::vector parameters; + for (int i = 0; i < c->num_params; i++) { + parameters.push_back(c->param[i]); + } + grf["parameters"] = parameters; + } +} + +/** + * Convert game-script information to JSON. + * + * @param survey The JSON object. + */ +static void SurveyGameScript(nlohmann::json &survey) +{ + if (Game::GetInfo() == nullptr) return; + + survey = fmt::format("{}.{}", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); +} + +#endif /* WITH_NLOHMANN_JSON */ + +/** + * Create the payload for the survey. + * + * @param reason The reason for sending the survey. + * @param for_preview Whether the payload is meant for preview. This indents the result, and filters out the id/key. + * @return std::string The JSON payload as string for the survey. + */ +std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview) +{ +#ifndef WITH_NLOHMANN_JSON + return ""; +#else + nlohmann::json survey; + + survey["schema"] = NETWORK_SURVEY_VERSION; + survey["reason"] = reason; + survey["id"] = _savegame_id; + +#ifdef SURVEY_KEY + /* We censor the key to avoid people trying to be "clever" and use it to send their own surveys. */ + survey["key"] = for_preview ? "(redacted)" : SURVEY_KEY; +#else + survey["key"] = ""; +#endif + + { + auto &info = survey["info"]; + SurveyOS(info["os"]); + info["os"]["hardware_concurrency"] = std::thread::hardware_concurrency(); + + SurveyOpenTTD(info["openttd"]); + SurveyConfiguration(info["configuration"]); + SurveyFont(info["font"]); + } + + { + auto &game = survey["game"]; + game["ticks"] = TimerGameTick::counter; + game["time"] = std::chrono::duration_cast(std::chrono::steady_clock::now() - _switch_mode_time).count(); + SurveyCompanies(game["companies"]); + SurveySettings(game["settings"]); + SurveyGrfs(game["grfs"]); + SurveyGameScript(game["game_script"]); + } + + /* For preview, we indent with 4 whitespaces to make things more readable. */ + int indent = for_preview ? 4 : -1; + return survey.dump(indent); +#endif /* WITH_NLOHMANN_JSON */ +} + +/** + * Transmit the survey. + * + * @param reason The reason for sending the survey. + * @param blocking Whether to block until the survey is sent. + */ +void NetworkSurveyHandler::Transmit(Reason reason, bool blocking) +{ + if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) { + Debug(net, 4, "Survey: not possible to send survey; most likely due to missing JSON library at compile-time"); + return; + } + + if (_settings_client.network.participate_survey != PS_YES) { + Debug(net, 5, "Survey: user is not participating in survey; skipping survey"); + return; + } + + Debug(net, 1, "Survey: sending survey results"); + NetworkHTTPSocketHandler::Connect(NetworkSurveyUriString(), this, this->CreatePayload(reason)); + + if (blocking) { + std::unique_lock lock(this->mutex); + /* Block no longer than 2 seconds. If we failed to send the survey in that time, so be it. */ + this->loaded.wait_for(lock, std::chrono::seconds(2)); + } +} + +void NetworkSurveyHandler::OnFailure() +{ + Debug(net, 1, "Survey: failed to send survey results"); + this->loaded.notify_all(); +} + +void NetworkSurveyHandler::OnReceiveData(const char *data, size_t length) +{ + if (data == nullptr) { + Debug(net, 1, "Survey: survey results sent"); + this->loaded.notify_all(); + } +} diff --git a/src/network/network_survey.h b/src/network/network_survey.h new file mode 100644 index 0000000000..c957108ecf --- /dev/null +++ b/src/network/network_survey.h @@ -0,0 +1,54 @@ +/* + * 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 network_survey.h Part of the network protocol handling opt-in survey. */ + +#ifndef NETWORK_SURVEY_H +#define NETWORK_SURVEY_H + +#include +#include +#include "core/http.h" + +/** + * Socket handler for the survey connection + */ +class NetworkSurveyHandler : public HTTPCallback { +protected: + void OnFailure() override; + void OnReceiveData(const char *data, size_t length) override; + bool IsCancelled() const override { return false; } + +public: + enum class Reason { + PREVIEW, ///< User is previewing the survey result. + LEAVE, ///< User is leaving the game (but not exiting the application). + EXIT, ///< User is exiting the application. + CRASH, ///< Game crashed. + }; + + void Transmit(Reason reason, bool blocking = false); + std::string CreatePayload(Reason reason, bool for_preview = false); + + constexpr static bool IsSurveyPossible() + { +#ifndef WITH_NLOHMANN_JSON + /* Without JSON library, we cannot send a payload; so we disable the survey. */ + return false; +#else + return true; +#endif /* WITH_NLOHMANN_JSON */ + } + +private: + std::mutex mutex; ///< Mutex for the condition variable. + std::condition_variable loaded; ///< Condition variable to wait for the survey to be sent. +}; + +extern NetworkSurveyHandler _survey; + +#endif /* NETWORK_SURVEY_H */ diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index b293cef711..2f3e5d2f09 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -925,7 +925,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { void OnClick(Point pt, int widget, int click_count) override { - if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_END) { + if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_CONTENT_END) { if (this->active_sel == nullptr && this->avail_sel == nullptr) return; ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != nullptr ? this->active_sel : this->avail_sel); @@ -1286,7 +1286,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { ); const GRFConfig *selected_config = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel; - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, selected_config == nullptr || !selected_config->GetTextfile(tft).has_value()); } this->SetWidgetDisabledState(WID_NS_OPEN_URL, selected_config == nullptr || StrEmpty(selected_config->GetURL())); diff --git a/src/openttd.cpp b/src/openttd.cpp index b048f1c6c9..62a55f223c 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -67,6 +67,7 @@ #include "framerate_type.h" #include "industry.h" #include "network/network_gui.h" +#include "network/network_survey.h" #include "misc_cmd.h" #include "timer/timer.h" #include "timer/timer_game_calendar.h" @@ -822,6 +823,7 @@ void HandleExitGameRequest() _exit_game = true; } else if (_settings_client.gui.autosave_on_exit) { DoExitSave(); + _survey.Transmit(NetworkSurveyHandler::Reason::EXIT, true); _exit_game = true; } else { AskExitGame(); @@ -1036,9 +1038,16 @@ void SwitchToMode(SwitchMode new_mode) /* When we change mode, reset the autosave. */ if (new_mode != SM_SAVE_GAME) ChangeAutosaveFrequency(true); + /* Transmit the survey if we were in normal-mode and not saving. It always means we leaving the current game. */ + if (_game_mode == GM_NORMAL && new_mode != SM_SAVE_GAME) _survey.Transmit(NetworkSurveyHandler::Reason::LEAVE); + + /* Keep track when we last switch mode. Used for survey, to know how long someone was in a game. */ + if (new_mode != SM_SAVE_GAME) _switch_mode_time = std::chrono::steady_clock::now(); + switch (new_mode) { case SM_EDITOR: // Switch to scenario editor MakeNewEditorWorld(); + GenerateSavegameId(); break; case SM_RELOADGAME: // Reload with what-ever started the game @@ -1055,11 +1064,13 @@ void SwitchToMode(SwitchMode new_mode) } MakeNewGame(false, new_mode == SM_NEWGAME); + GenerateSavegameId(); break; case SM_RESTARTGAME: // Restart --> 'Random game' with current settings case SM_NEWGAME: // New Game --> 'Random game' MakeNewGame(false, new_mode == SM_NEWGAME); + GenerateSavegameId(); break; case SM_LOAD_GAME: { // Load game, Play Scenario @@ -1083,18 +1094,21 @@ void SwitchToMode(SwitchMode new_mode) case SM_RESTART_HEIGHTMAP: // Load a heightmap and start a new game from it with current settings case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it MakeNewGame(true, new_mode == SM_START_HEIGHTMAP); + GenerateSavegameId(); break; case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor SetLocalCompany(OWNER_NONE); GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); + GenerateSavegameId(); MarkWholeScreenDirty(); break; case SM_LOAD_SCENARIO: { // Load scenario from scenario editor if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_EDITOR, NO_DIRECTORY)) { SetLocalCompany(OWNER_NONE); + GenerateSavegameId(); _settings_newgame.game_creation.starting_year = TimerGameCalendar::year; /* Cancel the saveload pausing */ Command::Post(PM_PAUSED_SAVELOAD, false); @@ -1116,6 +1130,14 @@ void SwitchToMode(SwitchMode new_mode) ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL); BaseSounds::ini_set = BaseSounds::GetUsedSet()->name; } + if (_settings_client.network.participate_survey == PS_ASK) { + /* No matter how often you go back to the main menu, only ask the first time. */ + static bool asked_once = false; + if (!asked_once) { + asked_once = true; + ShowNetworkAskSurvey(); + } + } break; case SM_SAVE_GAME: // Save game. diff --git a/src/openttd.h b/src/openttd.h index 0c1547178c..282c0a033b 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -11,6 +11,7 @@ #define OPENTTD_H #include +#include #include "core/enum_type.hpp" /** Mode which defines the state of the game. */ @@ -53,6 +54,7 @@ enum DisplayOptions { extern GameMode _game_mode; extern SwitchMode _switch_mode; +extern std::chrono::steady_clock::time_point _switch_mode_time; extern std::atomic _exit_game; extern bool _save_config; @@ -86,6 +88,7 @@ void HandleExitGameRequest(); void SwitchToMode(SwitchMode new_mode); bool RequestNewGRFScan(struct NewGRFScanCallback *callback = nullptr); +void GenerateSavegameId(); void OpenBrowser(const char *url); void ChangeAutosaveFrequency(bool reset); diff --git a/src/os/macosx/CMakeLists.txt b/src/os/macosx/CMakeLists.txt index acb30baf88..a494825b49 100644 --- a/src/os/macosx/CMakeLists.txt +++ b/src/os/macosx/CMakeLists.txt @@ -7,6 +7,7 @@ add_files( osx_stdafx.h string_osx.cpp string_osx.h + survey_osx.cpp CONDITION APPLE ) diff --git a/src/os/macosx/macos.h b/src/os/macosx/macos.h index 2a7a12a5fb..5dc6b3e095 100644 --- a/src/os/macosx/macos.h +++ b/src/os/macosx/macos.h @@ -38,6 +38,8 @@ bool IsMonospaceFont(CFStringRef name); void MacOSSetThreadName(const char *name); +uint64 MacOSGetPhysicalMemory(); + /** Deleter that calls CFRelease rather than deleting the pointer. */ template struct CFDeleter { diff --git a/src/os/macosx/macos.mm b/src/os/macosx/macos.mm index 90bcd6dc40..452b151e9c 100644 --- a/src/os/macosx/macos.mm +++ b/src/os/macosx/macos.mm @@ -272,3 +272,8 @@ void MacOSSetThreadName(const char *name) [ cur performSelector:@selector(setName:) withObject:[ NSString stringWithUTF8String:name ] ]; } } + +uint64 MacOSGetPhysicalMemory() +{ + return [ [ NSProcessInfo processInfo ] physicalMemory ]; +} diff --git a/src/os/macosx/survey_osx.cpp b/src/os/macosx/survey_osx.cpp new file mode 100644 index 0000000000..88edebd9f6 --- /dev/null +++ b/src/os/macosx/survey_osx.cpp @@ -0,0 +1,38 @@ +/* + * 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 survey_osx.cpp OSX implementation of OS-specific survey information. */ + +#ifdef WITH_NLOHMANN_JSON + +#include "../../stdafx.h" + +#include "../../3rdparty/fmt/format.h" +#include "macos.h" + +#include +#include + +#include "../../safeguards.h" + +void SurveyOS(nlohmann::json &json) +{ + int ver_maj, ver_min, ver_bug; + GetMacOSVersion(&ver_maj, &ver_min, &ver_bug); + + const NXArchInfo *arch = NXGetLocalArchInfo(); + + json["os"] = "MacOS"; + json["release"] = fmt::format("{}.{}.{}", ver_maj, ver_min, ver_bug); + json["machine"] = arch != nullptr ? arch->description : "unknown"; + json["min_ver"] = MAC_OS_X_VERSION_MIN_REQUIRED; + json["max_ver"] = MAC_OS_X_VERSION_MAX_ALLOWED; + + json["memory"] = MacOSGetPhysicalMemory(); +} + +#endif /* WITH_NLOHMANN_JSON */ diff --git a/src/os/unix/CMakeLists.txt b/src/os/unix/CMakeLists.txt index a95d8ce2db..acdc73831f 100644 --- a/src/os/unix/CMakeLists.txt +++ b/src/os/unix/CMakeLists.txt @@ -1,5 +1,6 @@ add_files( crashlog_unix.cpp + survey_unix.cpp CONDITION UNIX AND NOT APPLE AND NOT OPTION_OS2 ) diff --git a/src/os/unix/survey_unix.cpp b/src/os/unix/survey_unix.cpp new file mode 100644 index 0000000000..d86b58e98c --- /dev/null +++ b/src/os/unix/survey_unix.cpp @@ -0,0 +1,38 @@ +/* + * 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 survey_unix.cpp Unix implementation of OS-specific survey information. */ + +#ifdef WITH_NLOHMANN_JSON + +#include "../../stdafx.h" + +#include +#include +#include + +#include "../../safeguards.h" + +void SurveyOS(nlohmann::json &json) +{ + struct utsname name; + if (uname(&name) < 0) { + json["os"] = "Unix"; + return; + } + + json["os"] = name.sysname; + json["release"] = name.release; + json["machine"] = name.machine; + json["version"] = name.version; + + long pages = sysconf(_SC_PHYS_PAGES); + long page_size = sysconf(_SC_PAGE_SIZE); + json["memory"] = pages * page_size; +} + +#endif /* WITH_NLOHMANN_JSON */ diff --git a/src/os/windows/CMakeLists.txt b/src/os/windows/CMakeLists.txt index a1b73a6d8f..9215514fa2 100644 --- a/src/os/windows/CMakeLists.txt +++ b/src/os/windows/CMakeLists.txt @@ -4,6 +4,7 @@ add_files( font_win32.h string_uniscribe.cpp string_uniscribe.h + survey_win.cpp win32.cpp win32.h CONDITION WIN32 diff --git a/src/os/windows/survey_win.cpp b/src/os/windows/survey_win.cpp new file mode 100644 index 0000000000..407ddb31d4 --- /dev/null +++ b/src/os/windows/survey_win.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 survey_win.cpp Windows implementation of OS-specific survey information. */ + +#ifdef WITH_NLOHMANN_JSON + +#include "../../stdafx.h" + +#include "../../3rdparty/fmt/format.h" + +#include +#include + +#include "../../safeguards.h" + +void SurveyOS(nlohmann::json &json) +{ + _OSVERSIONINFOA os; + os.dwOSVersionInfoSize = sizeof(os); + GetVersionExA(&os); + + json["os"] = "Windows"; + json["release"] = fmt::format("{}.{}.{} ({})", os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion); + + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + + json["memory"] = status.ullTotalPhys; +} + +#endif /* WITH_NLOHMANN_JSON */ diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 3f27b6c23f..15213ca7d0 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3224,6 +3224,10 @@ bool AfterLoadGame() for (Station *st : Station::Iterate()) UpdateStationAcceptance(st, false); } + if (IsSavegameVersionBefore(SLV_SAVEGAME_ID)) { + GenerateSavegameId(); + } + if (IsSavegameVersionBefore(SLV_AI_START_DATE)) { /* For older savegames, we don't now the actual interval; so set it to the newgame value. */ _settings_game.difficulty.competitors_interval = _settings_newgame.difficulty.competitors_interval; diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp index 5ac6e93b02..1a147c25ff 100644 --- a/src/saveload/misc_sl.cpp +++ b/src/saveload/misc_sl.cpp @@ -29,6 +29,7 @@ extern TileIndex _cur_tileloop_tile; extern uint16 _disaster_delay; extern byte _trees_tick_ctr; +extern std::string _savegame_id; /* Keep track of current game position */ int _saved_scrollpos_x; @@ -87,6 +88,7 @@ static const SaveLoad _date_desc[] = { SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8), SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION), + SLEG_CONDSSTR("id", _savegame_id, SLE_STR, SLV_SAVEGAME_ID, SL_MAX_VERSION), /* For older savegames, we load the current value as the "period"; afterload will set the "fired" and "elapsed". */ SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109), SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_UINT32, SLV_109, SLV_AI_START_DATE), diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index a30033078e..42729a5fb4 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -353,6 +353,7 @@ enum SaveLoadVersion : uint16 { SLV_EXTEND_VEHICLE_RANDOM, ///< 310 PR#10701 Extend vehicle random bits. SLV_EXTEND_ENTITY_MAPPING, ///< 311 PR#10672 Extend entity mapping range. SLV_DISASTER_VEH_STATE, ///< 312 PR#10798 Explicit storage of disaster vehicle state. + SLV_SAVEGAME_ID, ///< 313 PR#10719 Add an unique ID to every savegame (used to deduplicate surveys). SL_MAX_VERSION, ///< Highest possible saveload version }; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index ac7cfe09e1..9fe9c3a78a 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -41,6 +41,9 @@ #include "music/music_driver.hpp" #include "gui.h" #include "mixer.h" +#include "network/core/config.h" +#include "network/network_gui.h" +#include "network/network_survey.h" #include "safeguards.h" @@ -190,6 +193,8 @@ struct GameOptionsWindow : Window { this->OnInvalidateData(0); this->SetTab(WID_GO_TAB_GENERAL); + + if constexpr (!NetworkSurveyHandler::IsSurveyPossible()) this->GetWidget(WID_GO_SURVEY_SEL)->SetDisplayedPlane(SZSP_NONE); } void Close() override @@ -464,19 +469,19 @@ struct GameOptionsWindow : Window { void OnClick(Point pt, int widget, int click_count) override { - if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_END) { + if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_CONTENT_END) { if (BaseGraphics::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS); return; } - if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_END) { + if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_CONTENT_END) { if (BaseSounds::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS); return; } - if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_END) { + if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_CONTENT_END) { if (BaseMusic::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC); @@ -489,6 +494,30 @@ struct GameOptionsWindow : Window { this->SetTab(widget); break; + case WID_GO_SURVEY_PARTICIPATE_BUTTON: + switch (_settings_client.network.participate_survey) { + case PS_ASK: + case PS_NO: + _settings_client.network.participate_survey = PS_YES; + break; + + case PS_YES: + _settings_client.network.participate_survey = PS_NO; + break; + } + + this->SetWidgetLoweredState(WID_GO_SURVEY_PARTICIPATE_BUTTON, _settings_client.network.participate_survey == PS_YES); + this->SetWidgetDirty(WID_GO_SURVEY_PARTICIPATE_BUTTON); + break; + + case WID_GO_SURVEY_LINK_BUTTON: + OpenBrowser(NETWORK_SURVEY_DETAILS_LINK.c_str()); + break; + + case WID_GO_SURVEY_PREVIEW_BUTTON: + ShowSurveyResultTextfileWindow(); + break; + case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off /* try to toggle full-screen on/off */ if (!ToggleFullScreen(!_fullscreen)) { @@ -686,6 +715,7 @@ struct GameOptionsWindow : Window { void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; + this->SetWidgetLoweredState(WID_GO_SURVEY_PARTICIPATE_BUTTON, _settings_client.network.participate_survey == PS_YES); this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); this->SetWidgetLoweredState(WID_GO_VIDEO_ACCEL_BUTTON, _video_hw_accel); this->SetWidgetDisabledState(WID_GO_REFRESH_RATE_DROPDOWN, _video_vsync); @@ -701,7 +731,7 @@ struct GameOptionsWindow : Window { bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); - for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == nullptr || !BaseGraphics::GetUsedSet()->GetTextfile(tft).has_value()); this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == nullptr || !BaseSounds::GetUsedSet()->GetTextfile(tft).has_value()); this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == nullptr || !BaseMusic::GetUsedSet()->GetTextfile(tft).has_value()); @@ -739,6 +769,20 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), + + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GO_SURVEY_SEL), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME, STR_NULL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(1, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_PARTICIPATE_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_PREVIEW_BUTTON), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_SURVEY_LINK_BUTTON), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK, STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), EndContainer(), /* Graphics tab */ diff --git a/src/settings_type.h b/src/settings_type.h index 34284bc6a8..5b97fa78dc 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -63,13 +63,20 @@ enum IndustryDensity { ID_END, ///< Number of industry density settings. }; -/** Possible values for "userelayservice" setting. */ +/** Possible values for "use_relay_service" setting. */ enum UseRelayService { URS_NEVER = 0, URS_ASK, URS_ALLOW, }; +/** Possible values for "participate_survey" setting. */ +enum ParticipateSurvey { + PS_ASK = 0, + PS_NO, + PS_YES, +}; + /** Settings related to the difficulty of the game */ struct DifficultySettings { byte competitor_start_time; ///< Unused value, used to load old savegames. @@ -306,7 +313,8 @@ struct NetworkSettings { bool reload_cfg; ///< reload the config file before restarting std::string last_joined; ///< Last joined server bool no_http_content_downloads; ///< do not do content downloads over HTTP - UseRelayService use_relay_service; ///< Use relay service? + UseRelayService use_relay_service; ///< Use relay service? + ParticipateSurvey participate_survey; ///< Participate in the automated survey }; /** Settings related to the creation of games. */ diff --git a/src/table/settings/network_private_settings.ini b/src/table/settings/network_private_settings.ini index d984011903..f178cdcca8 100644 --- a/src/table/settings/network_private_settings.ini +++ b/src/table/settings/network_private_settings.ini @@ -8,6 +8,7 @@ [pre-amble] static constexpr std::initializer_list _use_relay_service{"never", "ask", "allow"}; +static constexpr std::initializer_list _participate_survey{"ask", "no", "yes"}; static const SettingVariant _network_private_settings_table[] = { [post-amble] @@ -16,6 +17,7 @@ static const SettingVariant _network_private_settings_table[] = { SDTC_BOOL = SDTC_BOOL( $var, $flags, $def, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $def, $max, $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup), SDTC_SSTR = SDTC_SSTR( $var, $type, $flags, $def, $length, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup), +SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $def, $max, $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $from, $to, $cat, $extra, $startup), [validation] SDTC_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); @@ -90,3 +92,12 @@ str = STR_CONFIG_SETTING_USE_RELAY_SERVICE strhelp = STR_CONFIG_SETTING_USE_RELAY_SERVICE_HELPTEXT strval = STR_CONFIG_SETTING_USE_RELAY_SERVICE_NEVER cat = SC_BASIC + +[SDTC_OMANY] +var = network.participate_survey +type = SLE_UINT8 +flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC +def = PS_ASK +min = PS_ASK +max = PS_YES +full = _participate_survey diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index ba067daead..210cdb3070 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -366,8 +366,21 @@ static void Xunzip(byte **bufp, size_t *sizep) if (StrStartsWith(sv_buf, u8"\ufeff")) sv_buf.remove_prefix(3); /* Replace any invalid characters with a question-mark. This copies the buf in the process. */ - this->text = StrMakeValid(sv_buf, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE | SVS_REPLACE_TAB_CR_NL_WITH_SPACE); + this->LoadText(sv_buf); free(buf); +} + +/** + * Load a text into the textfile viewer. + * + * This will split the text into newlines and stores it for fast drawing. + * + * @param buf The text to load. + */ +void TextfileWindow::LoadText(std::string_view buf) +{ + this->text = StrMakeValid(buf, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE | SVS_REPLACE_TAB_CR_NL_WITH_SPACE); + this->lines.clear(); /* Split the string on newlines. */ std::string_view p(this->text); @@ -406,7 +419,7 @@ std::optional GetTextfile(TextfileType type, Subdirectory dir, cons "changelog", "license", }; - static_assert(lengthof(prefixes) == TFT_END); + static_assert(lengthof(prefixes) == TFT_CONTENT_END); std::string_view prefix = prefixes[type]; diff --git a/src/textfile_gui.h b/src/textfile_gui.h index c233aba638..6b57abfa24 100644 --- a/src/textfile_gui.h +++ b/src/textfile_gui.h @@ -42,6 +42,9 @@ struct TextfileWindow : public Window, MissingGlyphSearcher { virtual void LoadTextfile(const std::string &textfile, Subdirectory dir); +protected: + void LoadText(std::string_view buf); + private: struct Line { int top; ///< Top scroll position. diff --git a/src/textfile_type.h b/src/textfile_type.h index ddb26f6a65..f45c016440 100644 --- a/src/textfile_type.h +++ b/src/textfile_type.h @@ -12,13 +12,15 @@ /** Additional text files accompanying Tar archives */ enum TextfileType { - TFT_BEGIN, + TFT_CONTENT_BEGIN, - TFT_README = TFT_BEGIN, ///< NewGRF readme - TFT_CHANGELOG, ///< NewGRF changelog - TFT_LICENSE, ///< NewGRF license + TFT_README = TFT_CONTENT_BEGIN, ///< Content readme + TFT_CHANGELOG, ///< Content changelog + TFT_LICENSE, ///< Content license - TFT_END, + TFT_CONTENT_END, // This marker is used to generate the above three buttons in sequence by various of places in the code. + + TFT_SURVEY_RESULT = TFT_CONTENT_END, ///< Survey result (preview) }; DECLARE_POSTFIX_INCREMENT(TextfileType) diff --git a/src/widget.cpp b/src/widget.cpp index 23924c2895..ae17fde96f 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1172,7 +1172,7 @@ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y this->widget_data = widget_data; this->tool_tip = tool_tip; this->scrollbar_index = -1; - this->text_colour = TC_BLACK; + this->text_colour = tp == WWT_CAPTION ? TC_WHITE : TC_BLACK; this->text_size = FS_NORMAL; this->align = SA_CENTER; } diff --git a/src/widgets/ai_widget.h b/src/widgets/ai_widget.h index 4d6418bcfe..3753941609 100644 --- a/src/widgets/ai_widget.h +++ b/src/widgets/ai_widget.h @@ -29,7 +29,7 @@ enum AIConfigWidgets { WID_AIC_CONFIGURE, ///< Change AI settings button. WID_AIC_CLOSE, ///< Close window button. WID_AIC_TEXTFILE, ///< Open AI readme, changelog (+1) or license (+2). - WID_AIC_CONTENT_DOWNLOAD = WID_AIC_TEXTFILE + TFT_END, ///< Download content button. + WID_AIC_CONTENT_DOWNLOAD = WID_AIC_TEXTFILE + TFT_CONTENT_END, ///< Download content button. }; #endif /* WIDGETS_AI_WIDGET_H */ diff --git a/src/widgets/game_widget.h b/src/widgets/game_widget.h index f791a43749..5694bc4607 100644 --- a/src/widgets/game_widget.h +++ b/src/widgets/game_widget.h @@ -20,7 +20,7 @@ enum GSConfigWidgets { WID_GSC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. WID_GSC_CHANGE, ///< Select another Game Script button. WID_GSC_TEXTFILE, ///< Open GS readme, changelog (+1) or license (+2). - WID_GSC_CONTENT_DOWNLOAD = WID_GSC_TEXTFILE + TFT_END, ///< Download content button. + WID_GSC_CONTENT_DOWNLOAD = WID_GSC_TEXTFILE + TFT_CONTENT_END, ///< Download content button. WID_GSC_ACCEPT, ///< Accept ("Close") button WID_GSC_RESET, ///< Reset button. }; diff --git a/src/widgets/network_content_widget.h b/src/widgets/network_content_widget.h index 49c8153d4a..c8092aefa8 100644 --- a/src/widgets/network_content_widget.h +++ b/src/widgets/network_content_widget.h @@ -36,7 +36,7 @@ enum NetworkContentListWidgets { WID_NCL_DETAILS, ///< Panel with content details. WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. - WID_NCL_SELECT_ALL = WID_NCL_TEXTFILE + TFT_END, ///< 'Select all' button. + WID_NCL_SELECT_ALL = WID_NCL_TEXTFILE + TFT_CONTENT_END, ///< 'Select all' button. WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. WID_NCL_UNSELECT, ///< 'Unselect all' button. WID_NCL_OPEN_URL, ///< 'Open url' button. diff --git a/src/widgets/network_widget.h b/src/widgets/network_widget.h index 058cb090b0..8bfc3818f5 100644 --- a/src/widgets/network_widget.h +++ b/src/widgets/network_widget.h @@ -119,4 +119,14 @@ enum NetworkAskRelayWidgets { WID_NAR_YES_ALWAYS, ///< "Yes, always" button. }; +/** Widgets of the #NetworkAskSurveyWindow class. */ +enum NetworkAskSurveyWidgets { + WID_NAS_CAPTION, ///< Caption of the window. + WID_NAS_TEXT, ///< Text in the window. + WID_NAS_PREVIEW, ///< "Preview" button. + WID_NAS_LINK, ///< "Details & Privacy" button. + WID_NAS_NO, ///< "No" button. + WID_NAS_YES, ///< "Yes" button. +}; + #endif /* WIDGETS_NETWORK_WIDGET_H */ diff --git a/src/widgets/newgrf_widget.h b/src/widgets/newgrf_widget.h index 7f5fefde06..03b81bb584 100644 --- a/src/widgets/newgrf_widget.h +++ b/src/widgets/newgrf_widget.h @@ -47,7 +47,7 @@ enum NewGRFStateWidgets { WID_NS_NEWGRF_INFO, ///< Panel for Info on selected NewGRF. WID_NS_OPEN_URL, ///< Open URL of NewGRF. WID_NS_NEWGRF_TEXTFILE, ///< Open NewGRF readme, changelog (+1) or license (+2). - WID_NS_SET_PARAMETERS = WID_NS_NEWGRF_TEXTFILE + TFT_END, ///< Open Parameters Window for selected NewGRF for editing parameters. + WID_NS_SET_PARAMETERS = WID_NS_NEWGRF_TEXTFILE + TFT_CONTENT_END, ///< Open Parameters Window for selected NewGRF for editing parameters. WID_NS_VIEW_PARAMETERS, ///< Open Parameters Window for selected NewGRF for viewing parameters. WID_NS_TOGGLE_PALETTE, ///< Toggle Palette of selected, active NewGRF. WID_NS_APPLY_CHANGES, ///< Apply changes to NewGRF config. diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index 8e324f0d55..5f372eaec5 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -28,23 +28,27 @@ enum GameOptionsWidgets { WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). - WID_GO_BASE_GRF_DESCRIPTION = WID_GO_BASE_GRF_TEXTFILE + TFT_END, ///< Description of selected base GRF. + WID_GO_BASE_GRF_DESCRIPTION = WID_GO_BASE_GRF_TEXTFILE + TFT_CONTENT_END, ///< Description of selected base GRF. WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. WID_GO_TEXT_SFX_VOLUME, ///< Sound effects volume label. WID_GO_BASE_SFX_VOLUME, ///< Change sound effects volume. WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). - WID_GO_BASE_SFX_DESCRIPTION = WID_GO_BASE_SFX_TEXTFILE + TFT_END, ///< Description of selected base SFX. + WID_GO_BASE_SFX_DESCRIPTION = WID_GO_BASE_SFX_TEXTFILE + TFT_CONTENT_END, ///< Description of selected base SFX. WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. WID_GO_TEXT_MUSIC_VOLUME, ///< Music volume label. WID_GO_BASE_MUSIC_VOLUME, ///< Change music volume. WID_GO_BASE_MUSIC_JUKEBOX, ///< Open the jukebox. WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). - WID_GO_BASE_MUSIC_DESCRIPTION = WID_GO_BASE_MUSIC_TEXTFILE + TFT_END, ///< Description of selected base music set. + WID_GO_BASE_MUSIC_DESCRIPTION = WID_GO_BASE_MUSIC_TEXTFILE + TFT_CONTENT_END, ///< Description of selected base music set. WID_GO_VIDEO_ACCEL_BUTTON, ///< Toggle for video acceleration. WID_GO_VIDEO_VSYNC_BUTTON, ///< Toggle for video vsync. WID_GO_REFRESH_RATE_DROPDOWN, ///< Dropdown for all available refresh rates. WID_GO_VIDEO_DRIVER_INFO, ///< Label showing details about the current video driver. + WID_GO_SURVEY_SEL, ///< Selection to hide survey if no JSON library is compiled in. + WID_GO_SURVEY_PARTICIPATE_BUTTON, ///< Toggle for participating in the automated survey. + WID_GO_SURVEY_LINK_BUTTON, ///< Button to open browser to go to the survey website. + WID_GO_SURVEY_PREVIEW_BUTTON, ///< Button to open a preview window with the survey results }; /** Widgets of the #GameSettingsWindow class. */ diff --git a/src/window_type.h b/src/window_type.h index a31150f21d..e35814e9e5 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -483,6 +483,12 @@ enum WindowClass { */ WC_NETWORK_ASK_RELAY, + /** + * Network ask survey window; %Window numbers: + * - 0 - #NetworkAskSurveyWidgets + */ + WC_NETWORK_ASK_SURVEY, + /** * Chatbox; %Window numbers: * - #DestType = #NetWorkChatWidgets From 199e41c762c52c3fff85e52853ef78b7332c7645 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 14 May 2023 23:31:03 +0200 Subject: [PATCH 44/58] Codechange: use default dtor instead of empty (#10826) --- src/base_consist.h | 2 +- src/blitter/32bpp_sse2.hpp | 2 +- src/blitter/base.hpp | 2 +- src/core/alloc_type.hpp | 2 +- src/crashlog.h | 2 +- src/disaster_vehicle.h | 2 +- src/driver.h | 2 +- src/effectvehicle_base.h | 2 +- src/fileio_func.h | 2 +- src/gfx_layout.h | 6 +++--- src/linkgraph/demands.h | 2 +- src/linkgraph/flowmapper.h | 4 ---- src/linkgraph/init.h | 5 ----- src/linkgraph/linkgraphschedule.h | 2 +- src/linkgraph/mcf.h | 5 ----- src/network/core/core.h | 2 +- src/network/core/http.h | 2 +- src/network/core/tcp_game.h | 2 +- src/network/network_content.h | 2 +- src/network/network_gui.cpp | 2 +- src/network/network_udp.cpp | 4 ++-- src/newgrf_commons.h | 2 +- src/newgrf_config.h | 2 +- src/newgrf_debug_gui.cpp | 2 +- src/newgrf_spritegroup.h | 6 +++--- src/news_type.h | 2 +- src/saveload/saveload.h | 4 ++-- src/script/api/script_list.cpp | 2 +- src/settings_gui.cpp | 2 +- src/settings_internal.h | 10 +--------- src/spriteloader/spriteloader.hpp | 4 ++-- src/strgen/strgen.h | 4 ++-- src/string_base.h | 2 +- src/strings_func.h | 2 +- src/widgets/dropdown_type.h | 2 +- 35 files changed, 40 insertions(+), 62 deletions(-) diff --git a/src/base_consist.h b/src/base_consist.h index 0249182dfb..da4b11dbed 100644 --- a/src/base_consist.h +++ b/src/base_consist.h @@ -29,7 +29,7 @@ struct BaseConsist { uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) - virtual ~BaseConsist() {} + virtual ~BaseConsist() = default; void CopyConsistPropertiesFrom(const BaseConsist *src); }; diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp index 445fa97eb5..2921955f59 100644 --- a/src/blitter/32bpp_sse2.hpp +++ b/src/blitter/32bpp_sse2.hpp @@ -29,7 +29,7 @@ /** Base methods for 32bpp SSE blitters. */ class Blitter_32bppSSE_Base { public: - virtual ~Blitter_32bppSSE_Base() {} + virtual ~Blitter_32bppSSE_Base() = default; struct MapValue { uint8 m; diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp index f33b99ba2e..0a90f6c661 100644 --- a/src/blitter/base.hpp +++ b/src/blitter/base.hpp @@ -208,7 +208,7 @@ public: */ virtual void PostResize() { }; - virtual ~Blitter() { } + virtual ~Blitter() = default; template void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel); }; diff --git a/src/core/alloc_type.hpp b/src/core/alloc_type.hpp index 773de58837..173c859f58 100644 --- a/src/core/alloc_type.hpp +++ b/src/core/alloc_type.hpp @@ -86,7 +86,7 @@ class ZeroedMemoryAllocator { public: ZeroedMemoryAllocator() {} - virtual ~ZeroedMemoryAllocator() {} + virtual ~ZeroedMemoryAllocator() = default; /** * Memory allocator for a single class instance. diff --git a/src/crashlog.h b/src/crashlog.h index 90a06310e6..e90b13b499 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -81,7 +81,7 @@ protected: public: /** Stub destructor to silence some compilers. */ - virtual ~CrashLog() {} + virtual ~CrashLog() = default; char *FillCrashLog(char *buffer, const char *last) const; bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const; diff --git a/src/disaster_vehicle.h b/src/disaster_vehicle.h index 0df9913e5d..c10bedb7d5 100644 --- a/src/disaster_vehicle.h +++ b/src/disaster_vehicle.h @@ -44,7 +44,7 @@ struct DisasterVehicle FINAL : public SpecializedVehicle FontMap; */ class ParagraphLayouter { public: - virtual ~ParagraphLayouter() {} + virtual ~ParagraphLayouter() = default; /** Visual run contains data about the bit of text with the same font. */ class VisualRun { public: - virtual ~VisualRun() {} + virtual ~VisualRun() = default; virtual const Font *GetFont() const = 0; virtual int GetGlyphCount() const = 0; virtual const GlyphID *GetGlyphs() const = 0; @@ -106,7 +106,7 @@ public: /** A single line worth of VisualRuns. */ class Line { public: - virtual ~Line() {} + virtual ~Line() = default; virtual int GetLeading() const = 0; virtual int GetWidth() const = 0; virtual int CountRuns() const = 0; diff --git a/src/linkgraph/demands.h b/src/linkgraph/demands.h index 6fe3768341..4b2eec12a7 100644 --- a/src/linkgraph/demands.h +++ b/src/linkgraph/demands.h @@ -37,7 +37,7 @@ public: /** * Virtual destructor has to be defined because of virtual Run(). */ - virtual ~DemandHandler() {} + virtual ~DemandHandler() = default; }; #endif /* DEMANDS_H */ diff --git a/src/linkgraph/flowmapper.h b/src/linkgraph/flowmapper.h index 90ccd9fe52..da7375b8a6 100644 --- a/src/linkgraph/flowmapper.h +++ b/src/linkgraph/flowmapper.h @@ -30,10 +30,6 @@ public: FlowMapper(bool scale) : scale(scale) {} virtual void Run(LinkGraphJob &job) const; - /** - * Virtual destructor has to be defined because of virtual Run(). - */ - virtual ~FlowMapper() {} private: /** diff --git a/src/linkgraph/init.h b/src/linkgraph/init.h index 377c886311..a627005162 100644 --- a/src/linkgraph/init.h +++ b/src/linkgraph/init.h @@ -17,11 +17,6 @@ public: * @param job Job to be initialized. */ virtual void Run(LinkGraphJob &job) const { job.Init(); } - - /** - * Virtual destructor has to be defined because of virtual Run(). - */ - virtual ~InitHandler() {} }; #endif /* INIT_H */ diff --git a/src/linkgraph/linkgraphschedule.h b/src/linkgraph/linkgraphschedule.h index fef49e98f2..1e76cda324 100644 --- a/src/linkgraph/linkgraphschedule.h +++ b/src/linkgraph/linkgraphschedule.h @@ -23,7 +23,7 @@ public: /** * Destroy the handler. Must be given due to virtual Run. */ - virtual ~ComponentHandler() {} + virtual ~ComponentHandler() = default; /** * Run the handler. A link graph handler must not read or write any data diff --git a/src/linkgraph/mcf.h b/src/linkgraph/mcf.h index a2e85243d5..a3981877ff 100644 --- a/src/linkgraph/mcf.h +++ b/src/linkgraph/mcf.h @@ -81,11 +81,6 @@ public: * @param graph Component to be calculated. */ virtual void Run(LinkGraphJob &job) const { Tpass pass(job); } - - /** - * Destructor. Has to be given because of virtual Run(). - */ - virtual ~MCFHandler() {} }; #endif /* MCF_H */ diff --git a/src/network/core/core.h b/src/network/core/core.h index 84d5b62013..712687022a 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -48,7 +48,7 @@ public: NetworkSocketHandler() { this->has_quit = false; } /** Close the socket when destructing the socket handler */ - virtual ~NetworkSocketHandler() {} + virtual ~NetworkSocketHandler() = default; /** * Mark the connection as closed. diff --git a/src/network/core/http.h b/src/network/core/http.h index d851faf9c6..7bb03bc346 100644 --- a/src/network/core/http.h +++ b/src/network/core/http.h @@ -42,7 +42,7 @@ struct HTTPCallback { virtual bool IsCancelled() const = 0; /** Silentium */ - virtual ~HTTPCallback() {} + virtual ~HTTPCallback() = default; }; /** Base socket handler for HTTP traffic. */ diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index cd0facd781..4bcf1fb07d 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -518,7 +518,7 @@ public: * @param status The reason the connection got closed. */ virtual NetworkRecvStatus CloseConnection(NetworkRecvStatus status) = 0; - virtual ~NetworkGameSocketHandler() {} + virtual ~NetworkGameSocketHandler() = default; /** * Sets the client info for this socket handler. diff --git a/src/network/network_content.h b/src/network/network_content.h index 8a2877f904..a11d29b991 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -57,7 +57,7 @@ struct ContentCallback { virtual void OnDownloadComplete(ContentID cid) {} /** Silentium */ - virtual ~ContentCallback() {} + virtual ~ContentCallback() = default; }; /** diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 6353b899d2..68c00b15b1 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1444,7 +1444,7 @@ public: this->height = d.height + WidgetDimensions::scaled.framerect.Vertical(); this->width = d.width + WidgetDimensions::scaled.framerect.Horizontal(); } - virtual ~ButtonCommon() {} + virtual ~ButtonCommon() = default; /** * OnClick handler for when the button is pressed. diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 6aed7d0f10..4f4c1b8b98 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -70,7 +70,7 @@ public: * @param addresses The addresses to bind on. */ ServerNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {} - virtual ~ServerNetworkUDPSocketHandler() {} + virtual ~ServerNetworkUDPSocketHandler() = default; }; void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) @@ -88,7 +88,7 @@ class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override; public: - virtual ~ClientNetworkUDPSocketHandler() {} + virtual ~ClientNetworkUDPSocketHandler() = default; }; void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index 06e5fb5f7c..4a4df50707 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -204,7 +204,7 @@ public: std::vector mappings; ///< mapping of ids from grf files. Public out of convenience OverrideManagerBase(uint16 offset, uint16 maximum, uint16 invalid); - virtual ~OverrideManagerBase() {} + virtual ~OverrideManagerBase() = default; void ResetOverride(); void ResetMapping(); diff --git a/src/newgrf_config.h b/src/newgrf_config.h index db4b492a1d..d5d085b702 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -212,7 +212,7 @@ extern uint _missing_extra_graphics; ///< Number of sprites provided by the fal /** Callback for NewGRF scanning. */ struct NewGRFScanCallback { /** Make sure the right destructor gets called. */ - virtual ~NewGRFScanCallback() {} + virtual ~NewGRFScanCallback() = default; /** Called whenever the NewGRF scan completed. */ virtual void OnNewGRFsScanned() = 0; }; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index d656837e6b..f903771303 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -116,7 +116,7 @@ struct NIVariable { class NIHelper { public: /** Silence a warning. */ - virtual ~NIHelper() {} + virtual ~NIHelper() = default; /** * Is the item with the given index inspectable? diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index af28950a88..edd5af1bab 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -61,7 +61,7 @@ protected: virtual const SpriteGroup *Resolve(ResolverObject &object) const { return this; }; public: - virtual ~SpriteGroup() {} + virtual ~SpriteGroup() = default; uint32 nfo_line; SpriteGroupType type; @@ -289,7 +289,7 @@ struct ScopeResolver { ResolverObject &ro; ///< Surrounding resolver object. ScopeResolver(ResolverObject &ro) : ro(ro) {} - virtual ~ScopeResolver() {} + virtual ~ScopeResolver() = default; virtual uint32 GetRandomBits() const; virtual uint32 GetTriggers() const; @@ -318,7 +318,7 @@ struct ResolverObject { this->ResetState(); } - virtual ~ResolverObject() {} + virtual ~ResolverObject() = default; ScopeResolver default_scope; ///< Default implementation of the grf scope. diff --git a/src/news_type.h b/src/news_type.h index a1111ccaa0..c1e4586004 100644 --- a/src/news_type.h +++ b/src/news_type.h @@ -118,7 +118,7 @@ struct NewsTypeData { /** Container for any custom data that must be deleted after the news item has reached end-of-life. */ struct NewsAllocatedData { - virtual ~NewsAllocatedData() {} + virtual ~NewsAllocatedData() = default; }; diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 42729a5fb4..897e4cf367 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -424,7 +424,7 @@ struct ChunkHandler { ChunkHandler(uint32 id, ChunkType type) : id(id), type(type) {} - virtual ~ChunkHandler() {} + virtual ~ChunkHandler() = default; /** * Save the chunk. @@ -480,7 +480,7 @@ class SaveLoadHandler { public: std::optional> load_description; - virtual ~SaveLoadHandler() {} + virtual ~SaveLoadHandler() = default; /** * Save the object to disk. diff --git a/src/script/api/script_list.cpp b/src/script/api/script_list.cpp index 14bb9293d5..9df94a4821 100644 --- a/src/script/api/script_list.cpp +++ b/src/script/api/script_list.cpp @@ -28,7 +28,7 @@ public: /** * Virtual dtor, needed to mute warnings. */ - virtual ~ScriptListSorter() { } + virtual ~ScriptListSorter() = default; /** * Get the first item of the sorter. diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 9fe9c3a78a..076b2d088e 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -957,7 +957,7 @@ struct BaseSettingEntry { byte level; ///< Nesting level of this setting entry BaseSettingEntry() : flags(0), level(0) {} - virtual ~BaseSettingEntry() {} + virtual ~BaseSettingEntry() = default; virtual void Init(byte level = 0); virtual void FoldAll() {} diff --git a/src/settings_internal.h b/src/settings_internal.h index 914c8a79fa..645ea24f2c 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -72,7 +72,7 @@ struct IniItem; struct SettingDesc { SettingDesc(const SaveLoad &save, SettingFlag flags, bool startup) : flags(flags), startup(startup), save(save) {} - virtual ~SettingDesc() {} + virtual ~SettingDesc() = default; SettingFlag flags; ///< Handles how a setting would show up in the GUI (text/currency, etc.). bool startup; ///< Setting has to be loaded directly at startup?. @@ -155,7 +155,6 @@ struct IntSettingDesc : SettingDesc { SettingDesc(save, flags, startup), def(def), min(min), max(max), interval(interval), str(str), str_help(str_help), str_val(str_val), cat(cat), pre_check(pre_check), post_callback(post_callback) {} - virtual ~IntSettingDesc() {} int32 def; ///< default value given when none is present int32 min; ///< minimum values @@ -196,7 +195,6 @@ struct BoolSettingDesc : IntSettingDesc { PreChangeCheck pre_check, PostChangeCallback post_callback) : IntSettingDesc(save, flags, startup, def, 0, 1, 0, str, str_help, str_val, cat, pre_check, post_callback) {} - virtual ~BoolSettingDesc() {} bool IsBoolSetting() const override { return true; } size_t ParseValue(const char *str) const override; @@ -217,8 +215,6 @@ struct OneOfManySettingDesc : IntSettingDesc { for (auto one : many) this->many.push_back(one); } - virtual ~OneOfManySettingDesc() {} - std::vector many; ///< possible values for this type OnConvert *many_cnvt; ///< callback procedure when loading value mechanism fails @@ -237,7 +233,6 @@ struct ManyOfManySettingDesc : OneOfManySettingDesc { std::initializer_list many, OnConvert *many_cnvt) : OneOfManySettingDesc(save, flags, startup, def, (1 << many.size()) - 1, str, str_help, str_val, cat, pre_check, post_callback, many, many_cnvt) {} - virtual ~ManyOfManySettingDesc() {} size_t ParseValue(const char *str) const override; void FormatValue(char *buf, const char *last, const void *object) const override; @@ -264,7 +259,6 @@ struct StringSettingDesc : SettingDesc { uint32 max_length, PreChangeCheck pre_check, PostChangeCallback post_callback) : SettingDesc(save, flags, startup), def(def == nullptr ? "" : def), max_length(max_length), pre_check(pre_check), post_callback(post_callback) {} - virtual ~StringSettingDesc() {} std::string def; ///< Default value given when none is present uint32 max_length; ///< Maximum length of the string, 0 means no maximum length @@ -288,7 +282,6 @@ private: struct ListSettingDesc : SettingDesc { ListSettingDesc(const SaveLoad &save, SettingFlag flags, bool startup, const char *def) : SettingDesc(save, flags, startup), def(def) {} - virtual ~ListSettingDesc() {} const char *def; ///< default value given when none is present @@ -301,7 +294,6 @@ struct ListSettingDesc : SettingDesc { struct NullSettingDesc : SettingDesc { NullSettingDesc(const SaveLoad &save) : SettingDesc(save, SF_NOT_IN_CONFIG, false) {} - virtual ~NullSettingDesc() {} void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } void ParseValue(const IniItem *item, void *object) const override { NOT_REACHED(); } diff --git a/src/spriteloader/spriteloader.hpp b/src/spriteloader/spriteloader.hpp index fdd8be8612..38b6186eeb 100644 --- a/src/spriteloader/spriteloader.hpp +++ b/src/spriteloader/spriteloader.hpp @@ -77,14 +77,14 @@ public: */ virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, byte control_flags) = 0; - virtual ~SpriteLoader() { } + virtual ~SpriteLoader() = default; }; /** Interface for something that can encode a sprite. */ class SpriteEncoder { public: - virtual ~SpriteEncoder() { } + virtual ~SpriteEncoder() = default; /** * Can the sprite encoder make use of RGBA sprites? diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index cf569fd2bc..4ea9c328d5 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -104,7 +104,7 @@ struct HeaderWriter { virtual void Finalise(const StringData &data) = 0; /** Especially destroy the subclasses. */ - virtual ~HeaderWriter() {}; + virtual ~HeaderWriter() = default; void WriteHeader(const StringData &data); }; @@ -131,7 +131,7 @@ struct LanguageWriter { virtual void Finalise() = 0; /** Especially destroy the subclasses. */ - virtual ~LanguageWriter() {} + virtual ~LanguageWriter() = default; virtual void WriteLength(uint length); virtual void WriteLang(const StringData &data); diff --git a/src/string_base.h b/src/string_base.h index d7414c9156..6546d3cdae 100644 --- a/src/string_base.h +++ b/src/string_base.h @@ -28,7 +28,7 @@ public: */ static std::unique_ptr Create(); - virtual ~StringIterator() {} + virtual ~StringIterator() = default; /** * Set a new iteration string. Must also be called if the string contents diff --git a/src/strings_func.h b/src/strings_func.h index 12f414961a..6ea9e46d47 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -257,7 +257,7 @@ bool StringIDSorter(const StringID &a, const StringID &b); class MissingGlyphSearcher { public: /** Make sure everything gets destructed right. */ - virtual ~MissingGlyphSearcher() {} + virtual ~MissingGlyphSearcher() = default; /** * Get the next string to search through. diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index 1414a03080..0d8951ef7b 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -25,7 +25,7 @@ public: bool masked; ///< Masked and unselectable item DropDownListItem(int result, bool masked) : result(result), masked(masked) {} - virtual ~DropDownListItem() {} + virtual ~DropDownListItem() = default; virtual bool Selectable() const { return false; } virtual uint Height(uint width) const { return FONT_HEIGHT_NORMAL; } From e4fd9d41d3a4812063f313ceed0536a2ba4a8362 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 14 May 2023 23:18:52 +0100 Subject: [PATCH 45/58] Codechange: Use std::any_of() (#10830) When the result of std::find_if is compared only with end() then '!= end()' is replaced with any_of(). Just... there's only one. --- src/group_gui.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index fd2e4759ec..9f72b22235 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -144,8 +144,7 @@ private: this->indents.push_back(indent); if (g->folded) { /* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */ - auto child = std::find_if(source.begin(), source.end(), [g](const Group *child){ return child->parent == g->index; }); - bool has_children = child != source.end(); + bool has_children = std::any_of(source.begin(), source.end(), [g](const Group *child){ return child->parent == g->index; }); Group::Get(g->index)->folded = has_children; } else { AddChildren(source, g->index, indent + 1); From 40f567d464ac6917bab94fed28c90c4b8ca0567d Mon Sep 17 00:00:00 2001 From: PeterN Date: Mon, 15 May 2023 18:57:50 +0100 Subject: [PATCH 46/58] Fix #10811: Crash getting row from non-resizable widget. (#10833) GetScrolled*FromWidget took line height from the widget's resize_y value, however not all widgets are resizable, resulting in a division-by-zero. Allow passing line height explicitly in cases where a widget is not resizable. --- src/airport_gui.cpp | 2 +- src/widget.cpp | 5 +++-- src/widget_type.h | 7 ++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index f8015e274a..2f577357f7 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -501,7 +501,7 @@ public: break; case WID_AP_AIRPORT_LIST: { - int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget); + int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height); if (num_clicked == INT_MAX) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); diff --git a/src/widget.cpp b/src/widget.cpp index ae17fde96f..9b215e6878 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2365,11 +2365,12 @@ void NWidgetViewport::UpdateViewportCoordinates(Window *w) * @param w The window the click was in. * @param widget Widget number of the widget clicked in. * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. + * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. */ -int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding) const +int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const { - uint pos = w->GetRowFromWidget(clickpos, widget, padding, -1); + uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height); if (pos != INT_MAX) pos += this->GetPosition(); return (pos >= this->GetCount()) ? INT_MAX : pos; } diff --git a/src/widget_type.h b/src/widget_type.h index e7bbbcd842..ca08f2f571 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -788,7 +788,7 @@ public: } } - int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const; + int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const; /** * Return an iterator pointing to the element of a scrolled widget that a user clicked in. @@ -797,13 +797,14 @@ public: * @param w The window the click was in. * @param widget Widget number of the widget clicked in. * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. + * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. * @return Iterator to the element clicked at. If clicked at a wrong position, returns as interator to the end of the container. */ template - typename Tcontainer::iterator GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window * const w, int widget, int padding = 0) const + typename Tcontainer::iterator GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const { assert(this->GetCount() == container.size()); // Scrollbar and container size must match. - int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding); + int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding, line_height); if (row == INT_MAX) return std::end(container); typename Tcontainer::iterator it = std::begin(container); From 389b66bd1653520cf11b3ff44dc481efb1585ace Mon Sep 17 00:00:00 2001 From: translators Date: Mon, 15 May 2023 18:40:31 +0000 Subject: [PATCH 47/58] Update: Translations from eints --- src/lang/afrikaans.txt | 4 +++- src/lang/arabic_egypt.txt | 4 +++- src/lang/basque.txt | 4 +++- src/lang/belarusian.txt | 4 +++- src/lang/brazilian_portuguese.txt | 4 +++- src/lang/bulgarian.txt | 4 +++- src/lang/catalan.txt | 4 +++- src/lang/chuvash.txt | 4 +++- src/lang/croatian.txt | 4 +++- src/lang/czech.txt | 4 +++- src/lang/danish.txt | 4 +++- src/lang/dutch.txt | 4 +++- src/lang/english_AU.txt | 4 +++- src/lang/english_US.txt | 4 +++- src/lang/esperanto.txt | 4 +++- src/lang/estonian.txt | 4 +++- src/lang/faroese.txt | 4 +++- src/lang/finnish.txt | 4 +++- src/lang/french.txt | 4 +++- src/lang/frisian.txt | 4 +++- src/lang/gaelic.txt | 4 +++- src/lang/galician.txt | 4 +++- src/lang/german.txt | 4 +++- src/lang/greek.txt | 4 +++- src/lang/hebrew.txt | 4 +++- src/lang/hindi.txt | 4 +++- src/lang/hungarian.txt | 4 +++- src/lang/icelandic.txt | 4 +++- src/lang/ido.txt | 4 +++- src/lang/indonesian.txt | 4 +++- src/lang/irish.txt | 4 +++- src/lang/italian.txt | 4 +++- src/lang/japanese.txt | 4 +++- src/lang/korean.txt | 4 +++- src/lang/latin.txt | 4 +++- src/lang/latvian.txt | 4 +++- src/lang/lithuanian.txt | 4 +++- src/lang/luxembourgish.txt | 4 +++- src/lang/macedonian.txt | 4 +++- src/lang/malay.txt | 4 +++- src/lang/maltese.txt | 4 +++- src/lang/marathi.txt | 4 +++- src/lang/norwegian_bokmal.txt | 4 +++- src/lang/norwegian_nynorsk.txt | 4 +++- src/lang/persian.txt | 4 +++- src/lang/polish.txt | 4 +++- src/lang/portuguese.txt | 4 +++- src/lang/romanian.txt | 4 +++- src/lang/russian.txt | 4 +++- src/lang/serbian.txt | 4 +++- src/lang/simplified_chinese.txt | 4 +++- src/lang/slovak.txt | 4 +++- src/lang/slovenian.txt | 4 +++- src/lang/spanish.txt | 4 +++- src/lang/spanish_MX.txt | 4 +++- src/lang/swedish.txt | 4 +++- src/lang/tamil.txt | 4 +++- src/lang/thai.txt | 4 +++- src/lang/traditional_chinese.txt | 4 +++- src/lang/turkish.txt | 4 +++- src/lang/ukrainian.txt | 4 +++- src/lang/urdu.txt | 4 +++- src/lang/vietnamese.txt | 4 +++- src/lang/welsh.txt | 4 +++- 64 files changed, 192 insertions(+), 64 deletions(-) diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 2e27f9f2d3..c11b554570 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -974,6 +974,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :ander + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Basis-grafikastel STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Kies die basis-grafikastel stel om te gebruik STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} verlore / korrupte ler{P "" s} @@ -2178,6 +2179,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klient Lys + STR_NETWORK_SPECTATORS :Aanskouers # Network set password @@ -4282,7 +4284,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Omvou di STR_TEXTFILE_VIEW_README :{BLACK}Besigtig readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Veranderinge-log STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisensie -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme van {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} veranderinge-log van {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lisensie van {STRING} diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 70cf18a00f..a8086688d4 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -971,6 +971,7 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}اختر + STR_GAME_OPTIONS_GRAPHICS :{BLACK}الرسومات STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}معدل تحديث الشاشة @@ -1995,6 +1996,7 @@ STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}هل أ STR_NETWORK_ASK_RELAY_NO :{BLACK}لا + STR_NETWORK_SPECTATORS :المشاهدين # Network set password @@ -3995,7 +3997,7 @@ STR_TEXTFILE_WRAP_TEXT :{WHITE}التف STR_TEXTFILE_VIEW_README :{BLACK}اعرض ملف التعليمات ريدمي STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}اعرض سجل التغييرات STR_TEXTFILE_VIEW_LICENCE :{BLACK}الرخصة -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}اقراني {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} سجل التغيير ل{STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}رخصة {STRING} diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 5f5033454e..312984cf93 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -945,6 +945,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :besteak + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Grafiko basea markatu STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Aukeratu erabili beharreko grafiko paketea STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} galdutako/hautsitako artxiboa{P "" k} @@ -2064,6 +2065,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Bezero zerrenda + STR_NETWORK_SPECTATORS :Ikusleak # Network set password @@ -4032,7 +4034,7 @@ STR_TEXTFILE_WRAP_TEXT :{WHITE}Testua t STR_TEXTFILE_VIEW_README :{BLACK}Ikusi "irakur nazazu" STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Aldaketak STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lizentzia -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} ren "irakur nazazu" artxiboa STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING}-aren aldaketak STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING} rako lizentzia diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 826e92a7f8..40500bae8e 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -1282,6 +1282,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :Iншае + STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Чашчыня абнаўлення экрана STR_GAME_OPTIONS_BASE_GRF :{BLACK}Набор базавай ґрафікі @@ -2507,6 +2508,7 @@ STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Адключы STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Адключыць гульца «{STRING}»? + STR_NETWORK_SPECTATORS :Назіральнікі # Network set password @@ -4638,7 +4640,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Пера STR_TEXTFILE_VIEW_README :{BLACK}Прагледзець iнструкцыю STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Журнал зьменаў STR_TEXTFILE_VIEW_LICENCE :{BLACK}Ліцэнзія -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} iнструкцыя {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} сьпiс зьменаў {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} ліцэнзія {STRING} diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 7a9700df47..5c1321da32 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Taxa de atualização da tela @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Não STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sim, apenas dessa vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sim, não perguntar novamente + STR_NETWORK_SPECTATORS :Espectadores # Network set password @@ -4652,7 +4654,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :[BLACK}Quebra l STR_TEXTFILE_VIEW_README :{BLACK}Ver o leia-me STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Log de mudanças STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licença -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} Leia-me de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} log de mudanças de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licença de {STRING} diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index 39335140a1..fc4aafa6e2 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -953,6 +953,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :друго + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Базов графичен набор STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Изберете базов графичен набор STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} липсващи/повредени файлове @@ -2108,6 +2109,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Списък с + STR_NETWORK_SPECTATORS :Наблюдатели # Network set password @@ -4111,7 +4113,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Реор STR_TEXTFILE_VIEW_README :{BLACK}Отвори readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Дневник на промените STR_TEXTFILE_VIEW_LICENCE :{BLACK}Лиценз -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} Дневник на промените на {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} лиценз на {STRING} diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 7c3bba4f7e..13d9464528 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :x3 STR_GAME_OPTIONS_GUI_SCALE_4X :x4 STR_GAME_OPTIONS_GUI_SCALE_5X :x5 + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gràfics STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Rati de refresc de la pantalla @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sí, aquest una vegada. STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sí, no ho preguntis més. + STR_NETWORK_SPECTATORS :Espectadors # Network set password @@ -4655,7 +4657,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ajusta e STR_TEXTFILE_VIEW_README :{BLACK}Veure llegeix-me STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Registre de canvis STR_TEXTFILE_VIEW_LICENCE :{BLACK}Llicència -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Llegeix-me del {STRING} de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Registre de canvis del {STRING} de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Llicència del {STRING} de {STRING} diff --git a/src/lang/chuvash.txt b/src/lang/chuvash.txt index 7a30d71599..d2b6ef6380 100644 --- a/src/lang/chuvash.txt +++ b/src/lang/chuvash.txt @@ -514,6 +514,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :расна + # Custom currency window @@ -997,6 +998,7 @@ STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Вырн + # Network set password # Network company info join/password @@ -1598,7 +1600,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN # Textfile window -###length 3 +###length 4 # Vehicle loading indicators diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 0e3a70bdac..6d82f3d8af 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -1076,6 +1076,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Osnovni set grafike STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Odaberi osnovni grafički set za igru STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} datotek{P a e a} nedostaj{P e u e}/korumpiran{P a e o} @@ -2316,6 +2317,7 @@ STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Jeste l STR_NETWORK_ASK_RELAY_CAPTION :{WHITE}Koristi relej? STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Da, samo ovaj put + STR_NETWORK_SPECTATORS :Promatrači # Network set password @@ -4468,7 +4470,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Posloži STR_TEXTFILE_VIEW_README :{BLACK}Pogledaj "pročitaj me" datoteku STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Zapis izmjena STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenca -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} "pročitaj me" datoteka od {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} zapis izmjena od {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licenca od {STRING} diff --git a/src/lang/czech.txt b/src/lang/czech.txt index ae438602d9..2de9771fed 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -1109,6 +1109,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafiky STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Obnovovací frekvence obrazovky @@ -2463,6 +2464,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ne STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ano, toto jednou STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ano, znovu se neptat + STR_NETWORK_SPECTATORS :Pozorovatelé # Network set password @@ -4717,7 +4719,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Zalomit STR_TEXTFILE_VIEW_README :{BLACK}Zobrazit readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Novinky ve verzi STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} změny ve verzi {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licence {STRING} diff --git a/src/lang/danish.txt b/src/lang/danish.txt index b47b60da5c..d567e728a8 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Skærm opdateringshastighed @@ -2401,6 +2402,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nej STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, denne gang STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, spørg ikke igen + STR_NETWORK_SPECTATORS :Tilskuere # Network set password @@ -4648,7 +4650,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ombryd t STR_TEXTFILE_VIEW_README :{BLACK}Se readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Ændringslog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licens -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme for {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} ændringslog for {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licens for {STRING} diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index b1b628aff3..fdde13e670 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Weergave STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Verversingssnelheid weergeven @@ -2402,6 +2403,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nee STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, deze keer STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, en vraag dit niet opnieuw + STR_NETWORK_SPECTATORS :Toeschouwers # Network set password @@ -4654,7 +4656,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Tekst aa STR_TEXTFILE_VIEW_README :{BLACK}Leesmij-bestand bekijken STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Wijzigingen STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licentie -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} leesmij van {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} wijzigingen van {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licentie van {STRING} diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 07b9a28865..a8c4bcc1bd 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphics STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Display refresh rate @@ -2402,6 +2403,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Yes, this once STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Yes, don't ask again + STR_NETWORK_SPECTATORS :Spectators # Network set password @@ -4654,7 +4656,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the STR_TEXTFILE_VIEW_README :{BLACK}View readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}License -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} license of {STRING} diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 0eb7e3dda4..f1a0705ed1 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphics STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Display refresh rate @@ -2402,6 +2403,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Yes, this once STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Yes, don't ask again + STR_NETWORK_SPECTATORS :Spectators # Network set password @@ -4654,7 +4656,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the STR_TEXTFILE_VIEW_README :{BLACK}View readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}License -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} license of {STRING} diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index b6465d78fe..afc72d1e3c 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -937,6 +937,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :alia + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Baza grafikaro STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Selektu la uzendan bazgrafikaron STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} mankanta{P "" j}/koruptita{P "" j} dosiero{P "" j} @@ -1811,6 +1812,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klientlisto + STR_NETWORK_SPECTATORS :Spektantoj # Network set password @@ -3544,7 +3546,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN STR_TEXTFILE_VIEW_README :{BLACK}Vidi legumin STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Ŝanĝarĥivo STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenco -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} legumin de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}-a ŝanĝarĥivo de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}-a licenco de {STRING} diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index 76f395de51..cf698362ed 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -1078,6 +1078,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Ekraani värskendussagedus @@ -2431,6 +2432,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ei STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Jah, ainult seekord STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}jah, ära küsi uuesti + STR_NETWORK_SPECTATORS :Vaatlejad # Network set password @@ -4677,7 +4679,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Murrab t STR_TEXTFILE_VIEW_README :{BLACK}Vaata abi STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Muudatuste logi STR_TEXTFILE_VIEW_LICENCE :{BLACK}Litsents -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} abi. STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} muudatuste logi {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} litsents {STRING} diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 12f9742be9..37c243436e 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -925,6 +925,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :annað + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base grafikk sett STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Vel ta base grafikk setti tú vil brúka STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} vantandi/oyðiløgd fíl{P a ir} @@ -1974,6 +1975,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Listi yvir klie + STR_NETWORK_SPECTATORS :Eygleiðarar # Network set password @@ -3685,7 +3687,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN STR_TEXTFILE_VIEW_README :{BLACK}Sjá readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Broytingarskrá STR_TEXTFILE_VIEW_LICENCE :{BLACK}Loyvi -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme fyri {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} broytingarskrá fyri {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} loyvi fyri {STRING} diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 7418d0467b..da20e95673 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3× STR_GAME_OPTIONS_GUI_SCALE_4X :4× STR_GAME_OPTIONS_GUI_SCALE_5X :5× + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafiikka STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Näytön virkistystaajuus @@ -2402,6 +2403,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ei STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Kyllä, tämän kerran STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Kyllä, älä kysy uudestaan + STR_NETWORK_SPECTATORS :Katsojat # Network set password @@ -4654,7 +4656,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Rivitä STR_TEXTFILE_VIEW_README :{BLACK}Näytä readme-tiedosto STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Muutosloki STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisenssi -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}:n {STRING} readme-tiedosto STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}:n {STRING} muutosloki STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}:n {STRING} lisenssi diff --git a/src/lang/french.txt b/src/lang/french.txt index 210a8d8e18..5b1c028314 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :x5 + STR_GAME_OPTIONS_GRAPHICS :{BLACK} Graphiques STR_GAME_OPTIONS_REFRESH_RATE :{BLACK} Taux de rafraîchissement de l'affichage @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Non STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Oui, cette fois uniquement STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Oui, ne plus me demander + STR_NETWORK_SPECTATORS :Spectateurs # Network set password @@ -4652,7 +4654,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Insérer STR_TEXTFILE_VIEW_README :{BLACK}Voir le Lisez-moi STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Journal des modifications STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Lisez-moi du module {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Journal des modifications pour le module {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licence du module {STRING} {STRING} diff --git a/src/lang/frisian.txt b/src/lang/frisian.txt index 0bf9212d83..b2cbf166e3 100644 --- a/src/lang/frisian.txt +++ b/src/lang/frisian.txt @@ -970,6 +970,7 @@ STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} + STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Byldferfaskingssnelheid STR_GAME_OPTIONS_BASE_GRF :{BLACK}Basisset for ôfbyldings @@ -2109,6 +2110,7 @@ STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Bisto d STR_NETWORK_ASK_RELAY_NO :{BLACK}Nee STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, net wer freegje + STR_NETWORK_SPECTATORS :Taskôgers # Network set password @@ -3881,7 +3883,7 @@ STR_TEXTFILE_WRAP_TEXT :{WHITE}Omwikkel STR_TEXTFILE_VIEW_README :{BLACK}Besjoch readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Feroarings STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisinsje -###length 3 +###length 4 STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} feroarings fan {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lisinsje fan {STRING} diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index 63bf8e42a1..3638eddb11 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -1158,6 +1158,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :Gnàthaichte + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Seata grafaigeachd bunasach STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Tagh an seata grafaigeachd bunasach a chleachdas tu STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} {P fhaidhle fhaidhle faidhlichean faidhle} a dhìth/coirbte @@ -2350,6 +2351,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liosta nan clia + STR_NETWORK_SPECTATORS :Amharcaichean # Network set password @@ -4425,7 +4427,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Paisg te STR_TEXTFILE_VIEW_README :{BLACK}Seall “Leugh mi” STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Loga nan atharraichean STR_TEXTFILE_VIEW_LICENCE :{BLACK}Ceadachas -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}“Leugh mi” {STRING} aig {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Loga atharraichean {STRING} aig {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Ceadachas {STRING} aig {STRING} diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 28a91f4dc3..332fc2c3bd 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -1024,6 +1024,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Amosar tasa de refresco @@ -2384,6 +2385,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Si, esta vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Si, non volvas preguntar + STR_NETWORK_SPECTATORS :Espectadores # Network set password @@ -4631,7 +4633,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Axusta o STR_TEXTFILE_VIEW_README :{BLACK}Ver "readme" STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Rexistro de cambios STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenza -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE} "readme" de {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Rexistro de cambios de {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE} licenza de {STRING}{STRING} diff --git a/src/lang/german.txt b/src/lang/german.txt index 115e0fc3aa..3e9f349793 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1023,6 +1023,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3× STR_GAME_OPTIONS_GUI_SCALE_4X :4× STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Bildwiederholrate @@ -2377,6 +2378,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nein STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, diesmal STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, nicht erneut fragen + STR_NETWORK_SPECTATORS :Zuschauer # Network set password @@ -4623,7 +4625,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Text des STR_TEXTFILE_VIEW_README :{BLACK}Liesmich anzeigen STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Änderungen STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lizenz -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}-Liesmich von {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}-Änderungen von {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}-Lizenz von {STRING} diff --git a/src/lang/greek.txt b/src/lang/greek.txt index be45f3ce8e..7022138599 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -1128,6 +1128,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Γραφικά STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Εμφάνιση ρυθμού ανανέωσης @@ -2478,6 +2479,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Όχι STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ναι, μόνο αυτή τη φορά STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ναι, μην ρωτήσεις ξανά + STR_NETWORK_SPECTATORS :Θεατές # Network set password @@ -4722,7 +4724,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Αναδ STR_TEXTFILE_VIEW_README :{BLACK}Εμφάνιση readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Ιστορικό αλλαγών STR_TEXTFILE_VIEW_LICENCE :{BLACK}Άδεια -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme του {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{G=m}{WHITE}{STRING} ιστορικό αλλαγών του {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} άδεια του {STRING} diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index a6ab3ea0c8..c9bf5b2ddc 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -980,6 +980,7 @@ STR_GAME_OPTIONS_GUI_SCALE_2X :2x STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}גרפיקה STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}עדכוני סמך מעל 60Hz עלולים להשפיע על ביצועים. @@ -2224,6 +2225,7 @@ STR_NETWORK_ASK_RELAY_CAPTION :{WHITE}השתמ STR_NETWORK_ASK_RELAY_NO :{BLACK}לא STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}כן, זה + STR_NETWORK_SPECTATORS :צופים # Network set password @@ -4327,7 +4329,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}אפשר STR_TEXTFILE_VIEW_README :{BLACK}צפה ב-"קרא אותי" STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}רשימת שינויים STR_TEXTFILE_VIEW_LICENCE :{BLACK}רשיון -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} "קרא אותי" של {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} רשימת שינויים של {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} רשיון של {STRING} diff --git a/src/lang/hindi.txt b/src/lang/hindi.txt index 879b665d60..422f92b57f 100644 --- a/src/lang/hindi.txt +++ b/src/lang/hindi.txt @@ -299,6 +299,7 @@ STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM} + # Custom currency window STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}एक पाउंड (£) की तुलना में अपनी मुद्रा का अवमूल्यन करें @@ -678,6 +679,7 @@ STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}सर + # Network set password # Network company info join/password @@ -1263,7 +1265,7 @@ STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} # Textfile window -###length 3 +###length 4 # Vehicle loading indicators diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 6eac5dc0b4..ba8d3aeed9 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -1105,6 +1105,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Képernyőfrissítési frekvencia @@ -2464,6 +2465,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nem STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Igen, most az egyszer STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Igen, ne kérdezd újra + STR_NETWORK_SPECTATORS :Megfigyelők # Network set password @@ -4716,7 +4718,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Szöveg STR_TEXTFILE_VIEW_README :{BLACK}Readme megtekintése STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Változások listája STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenc -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} readme-je STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}A(z) {STRING} {STRING} változásainak listája STR_TEXTFILE_LICENCE_CAPTION :{WHITE}A(z) {STRING} {STRING} licence diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 798af59b57..35743210eb 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -924,6 +924,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :annað + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Grunngrafík STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Nota grunngrafíkina STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} týnd{P "" ar} eða ónýt{P "" ar} skrá{P "" r} @@ -2012,6 +2013,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Listi yfir leik + STR_NETWORK_SPECTATORS :Áhorfendur # Network set password @@ -3918,7 +3920,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN STR_TEXTFILE_VIEW_README :{BLACK}Skoða lesskrá STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Breytiskrá STR_TEXTFILE_VIEW_LICENCE :{BLACK}Leyfi -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} lesskrá (readme) fyrir {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} breytiskrá (changelog) fyrir {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} leyfi fyrir {STRING} diff --git a/src/lang/ido.txt b/src/lang/ido.txt index 828b5c41d7..ddee0e4460 100644 --- a/src/lang/ido.txt +++ b/src/lang/ido.txt @@ -497,6 +497,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :altra + # Custom currency window @@ -865,6 +866,7 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x + # Network set password # Network company info join/password @@ -1459,7 +1461,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN # Textfile window -###length 3 +###length 4 # Vehicle loading indicators diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index a09156765a..bcbb80a5df 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Menampilkan kecepatan refresh @@ -2372,6 +2373,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Tidak STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ya, kali ini STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Iya, Jangan tanya lagi + STR_NETWORK_SPECTATORS :Penonton # Network set password @@ -4609,7 +4611,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Mengebat STR_TEXTFILE_VIEW_README :{BLACK}Lihat readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Catatan Perubahan STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisensi -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}keterangan {STRING} dari {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Catatan perubahan {STRING} dari {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Lisensi {STRING} dari {STRING} diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 45505e4a80..77422cd9cd 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -999,6 +999,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Cuir tic + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafaicí STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Ráta athnuachana na taispeána @@ -2329,6 +2330,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Níl STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Tá, an uair seo STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Tá, ná fiafraigh díom arís + STR_NETWORK_SPECTATORS :Féachadóirí # Network set password @@ -4527,7 +4529,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Timthria STR_TEXTFILE_VIEW_README :{BLACK}Amharc ar léigh mé STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Loga na n-athruithe STR_TEXTFILE_VIEW_LICENCE :{BLACK}Ceadúnas -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} léigh mé de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} loga athruithe de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} ceadúnas de {STRING} diff --git a/src/lang/italian.txt b/src/lang/italian.txt index 426e8fd569..fa90c2747e 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -1043,6 +1043,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafica STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Frequenza di aggiornameno dello schermo @@ -2437,6 +2438,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sì, questa volta STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sì, non chiederlo più + STR_NETWORK_SPECTATORS :Spettatori # Network set password @@ -4695,7 +4697,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Manda au STR_TEXTFILE_VIEW_README :{BLACK}Visualizza file leggimi STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenza -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}File leggimi del {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Changelog del {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licenza del {STRING} {STRING} diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index e34746d670..a8f651f6ad 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}グラフィクス STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}画面リフレッシュレート @@ -2401,6 +2402,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}拒否 STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}一度だけ STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}はい、二度と聞かないでください + STR_NETWORK_SPECTATORS :観覧者 # Network set password @@ -4648,7 +4650,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}ウィ STR_TEXTFILE_VIEW_README :{BLACK}Readmeを見る STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}変更履歴を見る STR_TEXTFILE_VIEW_LICENCE :{BLACK}ライセンス -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING}のReadme STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING}の変更履歴 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING}のライセンス diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 32d3751de1..4894f35a06 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}그래픽 STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}화면 주사율 @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}아니 STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}이번에만 사용 STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}항상 사용 + STR_NETWORK_SPECTATORS :관전자 # Network set password @@ -4652,7 +4654,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}본문 STR_TEXTFILE_VIEW_README :{BLACK}Readme 보기 STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}변경기록 STR_TEXTFILE_VIEW_LICENCE :{BLACK}저작권 -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING}의 Readme STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING}의 변경기록 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING}의 저작권 diff --git a/src/lang/latin.txt b/src/lang/latin.txt index cb87f41701..6ed858084a 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -1150,6 +1150,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :alia + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Fundamentum graphicum STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Eligere fundamentum graphicum adhibendum STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} fascicul{P us i} absen{P s tes}/corrupt{P us i} @@ -2352,6 +2353,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Index clientum + STR_NETWORK_SPECTATORS :Spectatores # Network set password @@ -4418,7 +4420,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Volvere STR_TEXTFILE_VIEW_README :{BLACK}Inspicere LegeMe STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Index Mutationum STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licentia -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} - {STRING} LegeMe STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} - {STRING} Index Mutationum STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} - {STRING} Licentia diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index cec14270fa..2034386279 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -1024,6 +1024,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Ekrāna atsvaidzes intensitāte @@ -2378,6 +2379,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nē STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Jā, vienreiz STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Jā, vairs nejautāt + STR_NETWORK_SPECTATORS :Novērotāji # Network set password @@ -4626,7 +4628,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Aplauzt STR_TEXTFILE_VIEW_README :{BLACK}Skatīt failu Lasi_mani STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Izmaiņu žurnāls STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} kopas {STRING} fails Lasi_mani STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} kopas {STRING} izmaiņu žurnāls STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} kopas {STRING} licence diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index f8e4e1944f..afee6ce5d2 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -1217,6 +1217,7 @@ STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Pažymė STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_4X :4x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Ekrano kadrų dažnis @@ -2550,6 +2551,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ne STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Taip, bet tik šįkart STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Taip, ir prašau nebeklausti + STR_NETWORK_SPECTATORS :Stebėtojai # Network set password @@ -4821,7 +4823,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Skaidyti STR_TEXTFILE_VIEW_README :{BLACK}Peržiūrėti SKAITYKMANE STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Pasikeitimai STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencija -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} aprašymas {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} pasikeitimai {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licencija {STRING} diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index 2beb5e3d5b..0183697a00 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphik STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Bildfrequenz @@ -2374,6 +2375,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nee STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Jo, des Kéier STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Jo, fro net nach eng Kéier + STR_NETWORK_SPECTATORS :Zuschauer # Network set password @@ -4619,7 +4621,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ännert STR_TEXTFILE_VIEW_README :{BLACK}Readme liesen STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lizenz -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme vun {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} Changelog vun {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} Lizenz vun {STRING} diff --git a/src/lang/macedonian.txt b/src/lang/macedonian.txt index bd199d3f49..d2b10cc4f3 100644 --- a/src/lang/macedonian.txt +++ b/src/lang/macedonian.txt @@ -815,6 +815,7 @@ STR_GAME_OPTIONS_CAPTION :{WHITE}Опци + # Custom currency window @@ -1219,6 +1220,7 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x + # Network set password # Network company info join/password @@ -1966,7 +1968,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN # Textfile window -###length 3 +###length 4 # Vehicle loading indicators diff --git a/src/lang/malay.txt b/src/lang/malay.txt index a28eb9d85c..6fdd7444d8 100644 --- a/src/lang/malay.txt +++ b/src/lang/malay.txt @@ -928,6 +928,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :lain + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Set grafik asas STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Pilih set grafik asas untuk digunakan STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} fail hilang/rosak @@ -1909,6 +1910,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Senarai klien + STR_NETWORK_SPECTATORS :Penyaksi # Network set password @@ -3829,7 +3831,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN STR_TEXTFILE_VIEW_README :{BLACK}Lihat readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}LogUbah STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lesen -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme untuk {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} LogUbah untuk {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lesen untuk {STRING} diff --git a/src/lang/maltese.txt b/src/lang/maltese.txt index 95e6e337fb..85ca34a6b9 100644 --- a/src/lang/maltese.txt +++ b/src/lang/maltese.txt @@ -430,6 +430,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :oħrajn + # Custom currency window @@ -793,6 +794,7 @@ STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} + # Network set password # Network company info join/password @@ -1331,7 +1333,7 @@ STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Исчи STR_TEXTFILE_VIEW_README :{BLACK}Прикажи ги чита-ми STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Промени се најавите STR_TEXTFILE_VIEW_LICENCE :{BLACK}Лиценца -###length 3 +###length 4 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} лиценца за {STRING} diff --git a/src/lang/marathi.txt b/src/lang/marathi.txt index 1942587181..43f6a74359 100644 --- a/src/lang/marathi.txt +++ b/src/lang/marathi.txt @@ -749,6 +749,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :अन्य + # Custom currency window @@ -1139,6 +1140,7 @@ STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} + # Network set password # Network company info join/password @@ -1753,7 +1755,7 @@ STR_AI_SETTINGS_SETTING :{STRING}: {ORAN # Textfile window -###length 3 +###length 4 # Vehicle loading indicators diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 39970979b8..9447a88bda 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -1005,6 +1005,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Merk av STR_GAME_OPTIONS_GUI_SCALE_2X :2x STR_GAME_OPTIONS_GUI_SCALE_3X :3x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafikk STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}VIs oppdateringsfrekvens @@ -2346,6 +2347,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nei STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, denne STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, ikke spør igjen + STR_NETWORK_SPECTATORS :Tilskuere # Network set password @@ -4549,7 +4551,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Bryt tek STR_TEXTFILE_VIEW_README :{BLACK}Se på hjelpefilen STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Endringslogg STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisens -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} hjelpefil til {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} endringslogg til {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lisens til {STRING} diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index 86c1c5f081..fcf0a1adca 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -955,6 +955,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :anna + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Grafikksett STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Vel grafikksett som skal nyttast STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} manglande/øydelagd{P "" e} fil{P "" er} @@ -2069,6 +2070,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste over klie + STR_NETWORK_SPECTATORS :Tilskodarar # Network set password @@ -4054,7 +4056,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Bryt tek STR_TEXTFILE_VIEW_README :{BLACK}Vis lesmeg STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Endringslogg STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisens -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} lesmeg for {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} endringslogg for {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lisens for {STRING} diff --git a/src/lang/persian.txt b/src/lang/persian.txt index b00801d621..3b9f8818f2 100644 --- a/src/lang/persian.txt +++ b/src/lang/persian.txt @@ -945,6 +945,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :دیگر + STR_GAME_OPTIONS_BASE_GRF :{BLACK}بسته گرافیک پایه STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}بسته گرافیک پایه را انتخاب کنید STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} فایل وجود ندارد یا خراب است @@ -1876,6 +1877,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}لیست STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}آیا از حذف شرکت «{COMPANY}» مطمئنید؟ + STR_NETWORK_SPECTATORS :تماشاگران # Network set password @@ -3478,7 +3480,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}متن STR_TEXTFILE_VIEW_README :{BLACK}مشاهده راهنما STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}گزارش تغییر STR_TEXTFILE_VIEW_LICENCE :{BLACK}گواهی -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}راهنمای {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} گزارش تغییرات {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} گواهی {STRING} diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 0d532fd637..98cea5f7b9 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1421,6 +1421,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Częstotliwość odświeżania obrazu @@ -2782,6 +2783,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nie STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Tak, ten jeden raz STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Tak, nie pytaj ponownie + STR_NETWORK_SPECTATORS :Widzowie # Network set password @@ -5040,7 +5042,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Zawiń t STR_TEXTFILE_VIEW_README :{BLACK}Odczytaj plik „readme” STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Lista zmian STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencja -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} - plik „readme” STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING} - lista zmian STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING} - licencja diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 3c641348c1..7ec204dac1 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Exibir taxa de atualização @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Não STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sim, desta vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sim, não perguntar novamente + STR_NETWORK_SPECTATORS :Espectadores # Network set password @@ -4655,7 +4657,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Envolve STR_TEXTFILE_VIEW_README :{BLACK}Ver leia-me STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Lista de alterações STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licença -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Leiame {STRING} de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Lista de alterações {STRING} de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licença {STRING} de {STRING} diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index 6a7b41c72c..afca5ec2dd 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafică STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Afișează rata de reîmprospătare @@ -2375,6 +2376,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nu STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Da, de data asta STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Da, nu mă mai întreba + STR_NETWORK_SPECTATORS :Spectatori # Network set password @@ -4620,7 +4622,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Încadre STR_TEXTFILE_VIEW_README :{BLACK}Vezi fișierul readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Listă modificări STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenţă -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}, fișier readme al {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}, lista de modificări a {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}, licența fișierului {STRING} diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 9f57366173..9dba08aa9e 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -1186,6 +1186,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Настройки графики STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Частота обновления экрана @@ -2553,6 +2554,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Нет STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Да, однократно STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Да, всегда + STR_NETWORK_SPECTATORS :Зрители # Network set password @@ -4841,7 +4843,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Пере STR_TEXTFILE_VIEW_README :{BLACK}Посмотреть инструкцию STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Список изменений STR_TEXTFILE_VIEW_LICENCE :{BLACK}Лицензия -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Инструкция к {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Список изменений к {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Лицензия к {STRING} {STRING} diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index 91a35b4e7c..4431535ce8 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -1217,6 +1217,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafike STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Frekvencija osvežavanja ekrana @@ -2567,6 +2568,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ne STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Da, jednom STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Da, ne pitaj ponovo + STR_NETWORK_SPECTATORS :Posmatrači # Network set password @@ -4820,7 +4822,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK} Prelomi STR_TEXTFILE_VIEW_README :{BLACK}Prikaži uputstvo STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Izmene STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenca -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} uputstvo za {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} izmene od {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licenca od {STRING} diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 5463560ce5..45615a00db 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3倍 STR_GAME_OPTIONS_GUI_SCALE_4X :4倍 STR_GAME_OPTIONS_GUI_SCALE_5X :5倍 + STR_GAME_OPTIONS_GRAPHICS :{BLACK}图像 STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}显示刷新率 @@ -2375,6 +2376,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}否 STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}是,本次请求 STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}是,不要再次询问 + STR_NETWORK_SPECTATORS :旁观者 # Network set password @@ -4619,7 +4621,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}強迫 STR_TEXTFILE_VIEW_README :{BLACK}查看说明 STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}更新日志 STR_TEXTFILE_VIEW_LICENCE :{BLACK}版权信息 -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} 的说明 STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING} 的更新日志 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING} 的版权信息 diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index 8d1b59e969..65e1b2a853 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -1091,6 +1091,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Obnovovacia frekvencia obrazovky @@ -2447,6 +2448,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nie STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Áno, tentokrát STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Áno, znova sa nepýtať + STR_NETWORK_SPECTATORS :Pozorovatelia # Network set password @@ -4693,7 +4695,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Zalamova STR_TEXTFILE_VIEW_README :{BLACK}Zobraziť readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Log zmien STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencia -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} "čítajma" {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} log zmien {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licencia {STRING} diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index 3f858f4c6c..80ebd98f9f 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -1110,6 +1110,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :drugo + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Osnovni komplet grafik STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Izberi osnovni komplet grafik za uporabo STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} manjkajoč{P a i e ih}/okvarjen{P a i e ih} datotek{P a i e ""} @@ -2305,6 +2306,7 @@ STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Spremeni STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Zagotovo želiš brcniti igralca '{STRING}'? + STR_NETWORK_SPECTATORS :Gledalci # Network set password @@ -4307,7 +4309,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Prilagod STR_TEXTFILE_VIEW_README :{BLACK}Prikaži preberi-me datoteko STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Zamenjaj dnevnik STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenca -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} preberi-me od {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} zamenjaj dnevnik od {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licenca od {STRING} diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index fa7bbba60c..363bcf3b4c 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -1023,6 +1023,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Mostrar frecuencia de actualización @@ -2375,6 +2376,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sí, sólo esta vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sí, y no preguntar de nuevo + STR_NETWORK_SPECTATORS :Espectadores # Network set password @@ -4616,7 +4618,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Limitar STR_TEXTFILE_VIEW_README :{BLACK}Ver léeme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Registro de cambios STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencia -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Léeme del {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Registro de cambios del {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licencia del {STRING} {STRING} diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 76baf78c0f..27f02562bb 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -1023,6 +1023,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Frecuencia de actualización @@ -2375,6 +2376,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sí, solo esta vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sí, no volver a preguntar + STR_NETWORK_SPECTATORS :Espectadores # Network set password @@ -4617,7 +4619,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Unir el STR_TEXTFILE_VIEW_README :{BLACK}Ver archivo Léeme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Registro de cambios STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencia -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Archivo Léeme del {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Registro de cambios del {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licencia del {STRING} {STRING} diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 4c51e5d8c3..6ada48888f 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Visa uppdateringsfrekvens @@ -2376,6 +2377,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nej STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, den här gången STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, fråga inte igen + STR_NETWORK_SPECTATORS :Åskådare # Network set password @@ -4621,7 +4623,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Bryt rad STR_TEXTFILE_VIEW_README :{BLACK}Visa manual STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Ändringshistorik STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licens -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE} {STRING}-manual för {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Ändringshistorik för {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licens för {STRING}{STRING} diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index 1b2a7af2ab..9f368f734d 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -969,6 +969,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}அசைவூட்டங்கள் STR_GAME_OPTIONS_REFRESH_RATE_ITEM :{NUM}Hz @@ -2111,6 +2112,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}இல STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}ஆம், இந்த முறை மட்டும் STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}ஆம், ஆனால் மீண்டும் கேட்காதே + STR_NETWORK_SPECTATORS :கவனிப்பவர்கள் # Network set password @@ -4126,7 +4128,7 @@ STR_TEXTFILE_WRAP_TEXT :{WHITE}உர STR_TEXTFILE_VIEW_README :{BLACK}படிக்க வேண்டியதை பார்வையிடு STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}மாற்றங்கள் பதிவேடு STR_TEXTFILE_VIEW_LICENCE :{BLACK}அனுமதி -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} இன் படிப்பு அறி STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING} இன் மாற்றங்கள் பதிவேடு STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING} இன் அனுமதி diff --git a/src/lang/thai.txt b/src/lang/thai.txt index cf8653d758..b190ad63cd 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -969,6 +969,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :อื่นๆ + STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}รีเฟรชเรทของหน้าจอ STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}หากตั้งรีเฟรชเรทไว้มากกว่า 60Hz ขึ้นไป อาจมีผลต่อประสิทธิภาพของเกมได้ @@ -2194,6 +2195,7 @@ STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}คุ STR_NETWORK_ASK_RELAY_CAPTION :{WHITE}ใช้รีเลย์มั้ย? STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}ใช่ครั้งเดียว + STR_NETWORK_SPECTATORS :ผู้ชม # Network set password @@ -4268,7 +4270,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}จั STR_TEXTFILE_VIEW_README :{BLACK}แสดง readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}ข้อมูลการอัพเดต STR_TEXTFILE_VIEW_LICENCE :{BLACK}การอนุญาต -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme ของ {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog ของ {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} การอนุญาตของ {STRING} diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index 66176232ab..bc4017a5d0 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -1022,6 +1022,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3倍 STR_GAME_OPTIONS_GUI_SCALE_4X :4倍 STR_GAME_OPTIONS_GUI_SCALE_5X :5倍 + STR_GAME_OPTIONS_GRAPHICS :{BLACK}圖形 STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}顯示畫面更新率 @@ -2376,6 +2377,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}否 STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}是,僅此一次 STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}是,且不再詢問 + STR_NETWORK_SPECTATORS :旁觀者 # Network set password @@ -4621,7 +4623,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}強迫 STR_TEXTFILE_VIEW_README :{BLACK}檢視Readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}修訂紀錄 STR_TEXTFILE_VIEW_LICENCE :{BLACK}授權條款 -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}{STRING}的 Readme STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}{STRING}的修訂紀錄 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}{STRING}的授權條款 diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index a35b93df61..84914cec33 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -1042,6 +1042,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafikler STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Tazeleme oranını görüntüle @@ -2403,6 +2404,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Hayır STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Evet, bu seferliğine STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Evet, bir daha sorma + STR_NETWORK_SPECTATORS :İzleyiciler # Network set password @@ -4655,7 +4657,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Metni, o STR_TEXTFILE_VIEW_README :{BLACK}Benioku dosyasını göster STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Değişiklik kayıtları STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisans -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} adlı {STRING}'nin benioku dosyası STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} adlı {STRING}'nin değişiklik kaydı STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} adlı {STRING}'nin lisansı diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index 1a36f91262..21f7ebd049 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -1150,6 +1150,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Графіка STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Показати швидкість оновлення @@ -2500,6 +2501,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ні STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Так, тільки раз STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Так, більше не питати + STR_NETWORK_SPECTATORS :Спостерігачі # Network set password @@ -4742,7 +4744,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Розм STR_TEXTFILE_VIEW_README :{BLACK}Інструкція STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Зміни STR_TEXTFILE_VIEW_LICENCE :{BLACK}Ліцензія -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Документація до {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Зміни в {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Ліцензія до {STRING} {STRING} diff --git a/src/lang/urdu.txt b/src/lang/urdu.txt index 38bddd848f..7e9d12674f 100644 --- a/src/lang/urdu.txt +++ b/src/lang/urdu.txt @@ -920,6 +920,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :دیگر + STR_GAME_OPTIONS_BASE_GRF :{BLACK}بُنیادی گرافک سیٹ STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}بُنیادی گرافک سیٹ اختیار کریں STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} @@ -1765,6 +1766,7 @@ STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}کلائ + STR_NETWORK_SPECTATORS :ناظرین # Network set password @@ -2730,7 +2732,7 @@ STR_AI_CONFIG_GAMESCRIPT :{SILVER}کھی STR_TEXTFILE_VIEW_README :{BLACK}مجھے پڑھیے فائل دیکھیں STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}تبدیلیوں کا ریکارڈ STR_TEXTFILE_VIEW_LICENCE :{BLACK}لائسنس -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} میں سے {STRING} مجھے پڑھیے STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} میں سے {STRING} تبدیلی کا ریکارڈ STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} میں سے {STRING} لائسنس diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 9b970910cd..35d2e460cc 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -1041,6 +1041,7 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x + STR_GAME_OPTIONS_GRAPHICS :{BLACK}Hình ảnh STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Tần số quét màn hình @@ -2402,6 +2403,7 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Không STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Đồng ý, chỉ lần này STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Đồng ý, đừng hỏi lại + STR_NETWORK_SPECTATORS :Người xem # Network set password @@ -4654,7 +4656,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ép ch STR_TEXTFILE_VIEW_README :{BLACK}Xem readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Lịch sử thay đổi STR_TEXTFILE_VIEW_LICENCE :{BLACK}Giấy phép -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Readme của {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Lịch sử thay đổi của {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Giấy phép của {STRING} {STRING} diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index 4c79ce874f..ac26439e08 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -957,6 +957,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :arall + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Set raffeg sylfaenol STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Dewiswch y set raffeg sylfaenol i'w defnyddio STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} ffeil ar goll/llygredig @@ -2150,6 +2151,7 @@ STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Anfon ne + STR_NETWORK_SPECTATORS :Gwylwyr # Network set password @@ -4174,7 +4176,7 @@ STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Amlapio STR_TEXTFILE_VIEW_README :{BLACK}Gweld dogfenyddiaeth STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Log Newidiadau STR_TEXTFILE_VIEW_LICENCE :{BLACK}Trwydded -###length 3 +###length 4 STR_TEXTFILE_README_CAPTION :{WHITE}Dogfenyddiaeth {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Log newidiadau {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Trwydded {STRING} {STRING} From 52a7c69974cbc9724ccbcce67897d92eb167c3dd Mon Sep 17 00:00:00 2001 From: Rubidium Date: Tue, 9 May 2023 23:10:38 +0200 Subject: [PATCH 48/58] Codechange: rework Gamelog changes from union to classes --- src/gamelog.cpp | 442 +++++++++++++++--------------------- src/gamelog.h | 2 +- src/gamelog_internal.h | 169 ++++++++++---- src/saveload/gamelog_sl.cpp | 98 +++++--- src/saveload/saveload.h | 52 +++++ 5 files changed, 432 insertions(+), 331 deletions(-) diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 6a4632fcb7..42c8290f71 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -32,11 +32,6 @@ extern byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! Gamelog _gamelog; ///< Gamelog instance -LoggedChange::~LoggedChange() -{ - if (this->ct == GLCT_SETTING) free(this->setting.name); -} - Gamelog::Gamelog() { this->data = std::make_unique(); @@ -50,26 +45,18 @@ Gamelog::~Gamelog() /** * Return the revision string for the current client version, for use in gamelog. - * The string returned is at most GAMELOG_REVISION_LENGTH bytes long. */ -static const char * GetGamelogRevisionString() +static std::string GetGamelogRevisionString() { - /* Allocate a buffer larger than necessary (git revision hash is 40 bytes) to avoid truncation later */ - static char gamelog_revision[48] = { 0 }; - static_assert(lengthof(gamelog_revision) > GAMELOG_REVISION_LENGTH); - if (IsReleasedVersion()) { return _openttd_revision; - } else if (gamelog_revision[0] == 0) { - /* Prefix character indication revision status */ - assert(_openttd_revision_modified < 3); - gamelog_revision[0] = "gum"[_openttd_revision_modified]; // g = "git", u = "unknown", m = "modified" - /* Append the revision hash */ - strecat(gamelog_revision, _openttd_revision_hash, lastof(gamelog_revision)); - /* Truncate string to GAMELOG_REVISION_LENGTH bytes */ - gamelog_revision[GAMELOG_REVISION_LENGTH - 1] = '\0'; } - return gamelog_revision; + + /* Prefix character indication revision status */ + assert(_openttd_revision_modified < 3); + return fmt::format("{}{}", + "gum"[_openttd_revision_modified], // g = "git", u = "unknown", m = "modified" + _openttd_revision_hash); } /** @@ -115,29 +102,28 @@ void Gamelog::Reset() /** * Adds the GRF ID, checksum and filename if found to the output iterator - * @param outputIterator The iterator to add the GRF info to. + * @param output_iterator The iterator to add the GRF info to. * @param last The end of the buffer * @param grfid GRF ID * @param md5sum array of md5sum to print, if known * @param gc GrfConfig, if known */ -template -static void AddGrfInfo(T &outputIterator, uint grfid, const uint8 *md5sum, const GRFConfig *gc) +static void AddGrfInfo(std::back_insert_iterator &output_iterator, uint32_t grfid, const uint8_t *md5sum, const GRFConfig *gc) { if (md5sum != nullptr) { - fmt::format_to(outputIterator, "GRF ID {:08X}, checksum {}", BSWAP32(grfid), MD5SumToString(md5sum)); + fmt::format_to(output_iterator, "GRF ID {:08X}, checksum {}", BSWAP32(grfid), MD5SumToString(md5sum)); } else { - fmt::format_to(outputIterator, "GRF ID {:08X}", BSWAP32(grfid)); + fmt::format_to(output_iterator, "GRF ID {:08X}", BSWAP32(grfid)); } if (gc != nullptr) { - fmt::format_to(outputIterator, ", filename: {} (md5sum matches)", gc->filename); + fmt::format_to(output_iterator, ", filename: {} (md5sum matches)", gc->filename); } else { gc = FindGRFConfig(grfid, FGCM_ANY); if (gc != nullptr) { - fmt::format_to(outputIterator, ", filename: {} (matches GRFID only)", gc->filename); + fmt::format_to(output_iterator, ", filename: {} (matches GRFID only)", gc->filename); } else { - fmt::format_to(outputIterator, ", unknown GRF"); + fmt::format_to(output_iterator, ", unknown GRF"); } } } @@ -156,22 +142,6 @@ static const char * const la_text[] = { static_assert(lengthof(la_text) == GLAT_END); -/** - * Information about the presence of a Grf at a certain point during gamelog history - * Note about missing Grfs: - * Changes to missing Grfs are not logged including manual removal of the Grf. - * So if the gamelog tells a Grf is missing we do not know whether it was readded or completely removed - * at some later point. - */ -struct GRFPresence{ - const GRFConfig *gc; ///< GRFConfig, if known - bool was_missing; ///< Grf was missing during some gameload in the past - - GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {} - GRFPresence() = default; -}; -typedef SmallMap GrfIDMapping; - /** * Prints active gamelog * @param proc the procedure to draw with @@ -183,153 +153,156 @@ void Gamelog::Print(std::function proc) proc("---- gamelog start ----"); for (const LoggedAction &la : this->data->action) { - assert((uint)la.at < GLAT_END); + assert(la.at < GLAT_END); proc(fmt::format("Tick {}: {}", la.tick, la_text[la.at])); - for (const LoggedChange &lc : la.change) { + for (auto &lc : la.change) { std::string message; - auto outputIterator = std::back_inserter(message); + auto output_iterator = std::back_inserter(message); + lc->FormatTo(output_iterator, grf_names, la.at); - switch (lc.ct) { - default: NOT_REACHED(); - case GLCT_MODE: - /* Changing landscape, or going from scenario editor to game or back. */ - fmt::format_to(outputIterator, "New game mode: {} landscape: {}", lc.mode.mode, lc.mode.landscape); - break; - - case GLCT_REVISION: - /* The game was loaded in a diffferent version than before. */ - fmt::format_to(outputIterator, "Revision text changed to {}, savegame version {}, ", - lc.revision.text, lc.revision.slver); + proc(message); + } + } - switch (lc.revision.modified) { - case 0: message += "not "; break; - case 1: message += "maybe "; break; - default: break; - } + proc("---- gamelog end ----"); +} - fmt::format_to(outputIterator, "modified, _openttd_newgrf_version = 0x{:08x}", lc.revision.newgrf); - break; - case GLCT_OLDVER: - /* The game was loaded from before 0.7.0-beta1. */ - message += "Conversion from "; - switch (lc.oldver.type) { - default: NOT_REACHED(); - case SGT_OTTD: - fmt::format_to(outputIterator, "OTTD savegame without gamelog: version {}, {}", - GB(lc.oldver.version, 8, 16), GB(lc.oldver.version, 0, 8)); - break; - - case SGT_TTO: - message += "TTO savegame"; - break; - - case SGT_TTD: - message += "TTD savegame"; - break; - - case SGT_TTDP1: - case SGT_TTDP2: - fmt::format_to(outputIterator, "TTDP savegame, {} format", - lc.oldver.type == SGT_TTDP1 ? "old" : "new"); - if (lc.oldver.version != 0) { - fmt::format_to(outputIterator, ", TTDP version {}.{}.{}.{}", - GB(lc.oldver.version, 24, 8), GB(lc.oldver.version, 20, 4), - GB(lc.oldver.version, 16, 4), GB(lc.oldver.version, 0, 16)); - } - break; - } - break; +/* virtual */ void LoggedChangeMode::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* Changing landscape, or going from scenario editor to game or back. */ + fmt::format_to(output_iterator, "New game mode: {} landscape: {}", this->mode, this->landscape); +} - case GLCT_SETTING: - /* A setting with the SF_NO_NETWORK flag got changed; these settings usually affect NewGRFs, such as road side or wagon speed limits. */ - fmt::format_to(outputIterator, "Setting changed: {} : {} -> {}", lc.setting.name, lc.setting.oldval, lc.setting.newval); - break; +/* virtual */ void LoggedChangeRevision::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* The game was loaded in a diffferent version than before. */ + fmt::format_to(output_iterator, "Revision text changed to {}, savegame version {}, ", + this->text, this->slver); - case GLCT_GRFADD: { - /* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */ - const GRFConfig *gc = FindGRFConfig(lc.grfadd.grfid, FGCM_EXACT, lc.grfadd.md5sum); - message += "Added NewGRF: "; - AddGrfInfo(outputIterator, lc.grfadd.grfid, lc.grfadd.md5sum, gc); - GrfIDMapping::Pair *gm = grf_names.Find(lc.grfrem.grfid); - if (gm != grf_names.End() && !gm->second.was_missing) message += ". Gamelog inconsistency: GrfID was already added!"; - grf_names[lc.grfadd.grfid] = gc; - break; - } + switch (this->modified) { + case 0: fmt::format_to(output_iterator, "not "); break; + case 1: fmt::format_to(output_iterator, "maybe "); break; + default: break; + } - case GLCT_GRFREM: { - /* A NewGRF got removed from the game, either manually or by it missing when loading the game. */ - GrfIDMapping::Pair *gm = grf_names.Find(lc.grfrem.grfid); - message += la.at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "; - AddGrfInfo(outputIterator, lc.grfrem.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) { - message += ". Gamelog inconsistency: GrfID was never added!"; - } else { - if (la.at == GLAT_LOAD) { - /* Missing grfs on load are not removed from the configuration */ - gm->second.was_missing = true; - } else { - grf_names.Erase(gm); - } - } - break; - } + fmt::format_to(output_iterator, "modified, _openttd_newgrf_version = 0x{:08x}", this->newgrf); +} - case GLCT_GRFCOMPAT: { - /* Another version of the same NewGRF got loaded. */ - const GRFConfig *gc = FindGRFConfig(lc.grfadd.grfid, FGCM_EXACT, lc.grfadd.md5sum); - message += "Compatible NewGRF loaded: "; - AddGrfInfo(outputIterator, lc.grfcompat.grfid, lc.grfcompat.md5sum, gc); - if (!grf_names.Contains(lc.grfcompat.grfid)) message += ". Gamelog inconsistency: GrfID was never added!"; - grf_names[lc.grfcompat.grfid] = gc; - break; - } +/* virtual */ void LoggedChangeOldVersion::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* The game was loaded from before 0.7.0-beta1. */ + fmt::format_to(output_iterator, "Conversion from "); + switch (this->type) { + default: NOT_REACHED(); + case SGT_OTTD: + fmt::format_to(output_iterator, "OTTD savegame without gamelog: version {}, {}", + GB(this->version, 8, 16), GB(this->version, 0, 8)); + break; - case GLCT_GRFPARAM: { - /* A parameter of a NewGRF got changed after the game was started. */ - GrfIDMapping::Pair *gm = grf_names.Find(lc.grfrem.grfid); - message += "GRF parameter changed: "; - AddGrfInfo(outputIterator, lc.grfparam.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) message += ". Gamelog inconsistency: GrfID was never added!"; - break; - } + case SGT_TTO: + fmt::format_to(output_iterator, "TTO savegame"); + break; - case GLCT_GRFMOVE: { - /* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */ - GrfIDMapping::Pair *gm = grf_names.Find(lc.grfrem.grfid); - fmt::format_to(outputIterator, "GRF order changed: {:08X} moved {} places {}", - BSWAP32(lc.grfmove.grfid), abs(lc.grfmove.offset), lc.grfmove.offset >= 0 ? "down" : "up" ); - AddGrfInfo(outputIterator, lc.grfmove.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) message += ". Gamelog inconsistency: GrfID was never added!"; - break; - } + case SGT_TTD: + fmt::format_to(output_iterator, "TTD savegame"); + break; - case GLCT_GRFBUG: { - /* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */ - GrfIDMapping::Pair *gm = grf_names.Find(lc.grfrem.grfid); - assert(lc.grfbug.bug == GBUG_VEH_LENGTH); + case SGT_TTDP1: + case SGT_TTDP2: + fmt::format_to(output_iterator, "TTDP savegame, {} format", + this->type == SGT_TTDP1 ? "old" : "new"); + if (this->version != 0) { + fmt::format_to(output_iterator, ", TTDP version {}.{}.{}.{}", + GB(this->version, 24, 8), GB(this->version, 20, 4), + GB(this->version, 16, 4), GB(this->version, 0, 16)); + } + break; + } +} - fmt::format_to(outputIterator, "Rail vehicle changes length outside a depot: GRF ID {:08X}, internal ID 0x{:X}", BSWAP32(lc.grfbug.grfid), (uint)lc.grfbug.data); - AddGrfInfo(outputIterator, lc.grfbug.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) message += ". Gamelog inconsistency: GrfID was never added!"; - break; - } +/* virtual */ void LoggedChangeSettingChanged::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* A setting with the SF_NO_NETWORK flag got changed; these settings usually affect NewGRFs, such as road side or wagon speed limits. */ + fmt::format_to(output_iterator, "Setting changed: {} : {} -> {}", this->name, this->oldval, this->newval); +} - case GLCT_EMERGENCY: - /* At one point the savegame was made during the handling of a game crash. - * The generic code already mentioned the emergency savegame, and there is no extra information to log. */ - break; - } +/* virtual */ void LoggedChangeGRFAdd::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */ + const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum); + fmt::format_to(output_iterator, "Added NewGRF: "); + AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc); + GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + if (gm != grf_names.End() && !gm->second.was_missing) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was already added!"); + grf_names[this->grfid] = gc; +} - proc(message); +/* virtual */ void LoggedChangeGRFRemoved::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* A NewGRF got removed from the game, either manually or by it missing when loading the game. */ + GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + fmt::format_to(output_iterator, action_type == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); + if (gm == grf_names.End()) { + fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + } else { + if (action_type == GLAT_LOAD) { + /* Missing grfs on load are not removed from the configuration */ + gm->second.was_missing = true; + } else { + grf_names.Erase(gm); } } +} - proc("---- gamelog end ----"); +/* virtual */ void LoggedChangeGRFChanged::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* Another version of the same NewGRF got loaded. */ + const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum); + fmt::format_to(output_iterator, "Compatible NewGRF loaded: "); + AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc); + if (!grf_names.Contains(this->grfid)) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + grf_names[this->grfid] = gc; +} + +/* virtual */ void LoggedChangeGRFParameterChanged::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* A parameter of a NewGRF got changed after the game was started. */ + GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + fmt::format_to(output_iterator, "GRF parameter changed: "); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); + if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); +} + +/* virtual */ void LoggedChangeGRFMoved::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */ + GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + fmt::format_to(output_iterator, "GRF order changed: {:08X} moved {} places {}", + BSWAP32(this->grfid), abs(this->offset), this->offset >= 0 ? "down" : "up" ); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); + if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); } +/* virtual */ void LoggedChangeGRFBug::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */ + GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + assert(this->bug == GBUG_VEH_LENGTH); + + fmt::format_to(output_iterator, "Rail vehicle changes length outside a depot: GRF ID {:08X}, internal ID 0x{:X}", BSWAP32(this->grfid), this->data); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); + if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); +} + +/* virtual */ void LoggedChangeEmergencySave::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) +{ + /* At one point the savegame was made during the handling of a game crash. + * The generic code already mentioned the emergency savegame, and there is no extra information to log. */ +} /** Print the gamelog data to the console. */ void Gamelog::PrintConsole() @@ -354,25 +327,20 @@ void Gamelog::PrintDebug(int level) /** - * Allocates new LoggedChange and new LoggedAction if needed. - * If there is no action active, nullptr is returned. - * @param ct type of change - * @return new LoggedChange, or nullptr if there is no action active + * Allocates a new LoggedAction if needed, and add the change when action is active. + * @param change The actual change. */ -LoggedChange *Gamelog::Change(GamelogChangeType ct) +void Gamelog::Change(std::unique_ptr &&change) { if (this->current_action == nullptr) { - if (this->action_type == GLAT_NONE) return nullptr; + if (this->action_type == GLAT_NONE) return; this->current_action = &this->data->action.emplace_back(); this->current_action->at = this->action_type; this->current_action->tick = TimerGameTick::counter; } - LoggedChange *lc = &this->current_action->change.emplace_back(); - lc->ct = ct; - - return lc; + this->current_action->change.push_back(std::move(change)); } @@ -384,7 +352,7 @@ void Gamelog::Emergency() /* Terminate any active action */ if (this->action_type != GLAT_NONE) this->StopAction(); this->StartAction(GLAT_EMERGENCY); - this->Change(GLCT_EMERGENCY); + this->Change(std::make_unique()); this->StopAction(); } @@ -394,8 +362,8 @@ void Gamelog::Emergency() bool Gamelog::TestEmergency() { for (const LoggedAction &la : this->data->action) { - for (const LoggedChange &lc : la.change) { - if (lc.ct == GLCT_EMERGENCY) return true; + for (const auto &lc : la.change) { + if (lc->ct == GLCT_EMERGENCY) return true; } } @@ -409,14 +377,8 @@ void Gamelog::Revision() { assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD); - LoggedChange *lc = this->Change(GLCT_REVISION); - if (lc == nullptr) return; - - memset(lc->revision.text, 0, sizeof(lc->revision.text)); - strecpy(lc->revision.text, GetGamelogRevisionString(), lastof(lc->revision.text)); - lc->revision.slver = SAVEGAME_VERSION; - lc->revision.modified = _openttd_revision_modified; - lc->revision.newgrf = _openttd_newgrf_version; + this->Change(std::make_unique( + GetGamelogRevisionString(), SAVEGAME_VERSION, _openttd_revision_modified, _openttd_newgrf_version)); } /** @@ -426,11 +388,7 @@ void Gamelog::Mode() { assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD || this->action_type == GLAT_CHEAT); - LoggedChange *lc = this->Change(GLCT_MODE); - if (lc == nullptr) return; - - lc->mode.mode = _game_mode; - lc->mode.landscape = _settings_game.game_creation.landscape; + this->Change(std::make_unique(_game_mode, _settings_game.game_creation.landscape)); } /** @@ -440,11 +398,8 @@ void Gamelog::Oldver() { assert(this->action_type == GLAT_LOAD); - LoggedChange *lc = this->Change(GLCT_OLDVER); - if (lc == nullptr) return; - - lc->oldver.type = _savegame_type; - lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version); + this->Change(std::make_unique(_savegame_type, + (_savegame_type == SGT_OTTD ? ((uint32_t)_sl_version << 8 | _sl_minor_version) : _ttdp_version))); } /** @@ -457,12 +412,7 @@ void Gamelog::Setting(const std::string &name, int32 oldval, int32 newval) { assert(this->action_type == GLAT_SETTING); - LoggedChange *lc = this->Change(GLCT_SETTING); - if (lc == nullptr) return; - - lc->setting.name = stredup(name.c_str()); - lc->setting.oldval = oldval; - lc->setting.newval = newval; + this->Change(std::make_unique(name, oldval, newval)); } @@ -472,17 +422,17 @@ void Gamelog::Setting(const std::string &name, int32 oldval, int32 newval) */ void Gamelog::TestRevision() { - const LoggedChange *rev = nullptr; + const LoggedChangeRevision *rev = nullptr; for (const LoggedAction &la : this->data->action) { - for (const LoggedChange &lc : la.change) { - if (lc.ct == GLCT_REVISION) rev = &lc; + for (const auto &lc : la.change) { + if (lc->ct == GLCT_REVISION) rev = static_cast(lc.get()); } } - if (rev == nullptr || strcmp(rev->revision.text, GetGamelogRevisionString()) != 0 || - rev->revision.modified != _openttd_revision_modified || - rev->revision.newgrf != _openttd_newgrf_version) { + if (rev == nullptr || rev->text != GetGamelogRevisionString() || + rev->modified != _openttd_revision_modified || + rev->newgrf != _openttd_newgrf_version) { this->Revision(); } } @@ -493,15 +443,15 @@ void Gamelog::TestRevision() */ void Gamelog::TestMode() { - const LoggedChange *mode = nullptr; + const LoggedChangeMode *mode = nullptr; for (const LoggedAction &la : this->data->action) { - for (const LoggedChange &lc : la.change) { - if (lc.ct == GLCT_MODE) mode = &lc; + for (const auto &lc : la.change) { + if (lc->ct == GLCT_MODE) mode = static_cast(lc.get()); } } - if (mode == nullptr || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) this->Mode(); + if (mode == nullptr || mode->mode != _game_mode || mode->landscape != _settings_game.game_creation.landscape) this->Mode(); } @@ -515,12 +465,7 @@ void Gamelog::GRFBug(uint32 grfid, byte bug, uint64 data) { assert(this->action_type == GLAT_GRFBUG); - LoggedChange *lc = this->Change(GLCT_GRFBUG); - if (lc == nullptr) return; - - lc->grfbug.data = data; - lc->grfbug.grfid = grfid; - lc->grfbug.bug = bug; + this->Change(std::make_unique(data, grfid, bug)); } /** @@ -535,10 +480,12 @@ void Gamelog::GRFBug(uint32 grfid, byte bug, uint64 data) bool Gamelog::GRFBugReverse(uint32 grfid, uint16 internal_id) { for (const LoggedAction &la : this->data->action) { - for (const LoggedChange &lc : la.change) { - if (lc.ct == GLCT_GRFBUG && lc.grfbug.grfid == grfid && - lc.grfbug.bug == GBUG_VEH_LENGTH && lc.grfbug.data == internal_id) { - return false; + for (const auto &lc : la.change) { + if (lc->ct == GLCT_GRFBUG) { + LoggedChangeGRFBug *bug = static_cast(lc.get()); + if (bug->grfid == grfid && bug->bug == GBUG_VEH_LENGTH && bug->data == internal_id) { + return false; + } } } } @@ -569,10 +516,7 @@ void Gamelog::GRFRemove(uint32 grfid) { assert(this->action_type == GLAT_LOAD || this->action_type == GLAT_GRF); - LoggedChange *lc = this->Change(GLCT_GRFREM); - if (lc == nullptr) return; - - lc->grfrem.grfid = grfid; + this->Change(std::make_unique(grfid)); } /** @@ -585,10 +529,7 @@ void Gamelog::GRFAdd(const GRFConfig *newg) if (!IsLoggableGrfConfig(newg)) return; - LoggedChange *lc = this->Change(GLCT_GRFADD); - if (lc == nullptr) return; - - lc->grfadd = newg->ident; + this->Change(std::make_unique(newg->ident)); } /** @@ -600,10 +541,7 @@ void Gamelog::GRFCompatible(const GRFIdentifier *newg) { assert(this->action_type == GLAT_LOAD || this->action_type == GLAT_GRF); - LoggedChange *lc = this->Change(GLCT_GRFCOMPAT); - if (lc == nullptr) return; - - lc->grfcompat = *newg; + this->Change(std::make_unique(*newg)); } /** @@ -615,11 +553,7 @@ void Gamelog::GRFMove(uint32 grfid, int32 offset) { assert(this->action_type == GLAT_GRF); - LoggedChange *lc = this->Change(GLCT_GRFMOVE); - if (lc == nullptr) return; - - lc->grfmove.grfid = grfid; - lc->grfmove.offset = offset; + this->Change(std::make_unique(grfid, offset)); } /** @@ -631,10 +565,7 @@ void Gamelog::GRFParameters(uint32 grfid) { assert(this->action_type == GLAT_GRF); - LoggedChange *lc = this->Change(GLCT_GRFPARAM); - if (lc == nullptr) return; - - lc->grfparam.grfid = grfid; + this->Change(std::make_unique(grfid)); } /** @@ -752,14 +683,16 @@ void Gamelog::GRFUpdate(const GRFConfig *oldc, const GRFConfig *newc) void Gamelog::Info(uint32 *last_ottd_rev, byte *ever_modified, bool *removed_newgrfs) { for (const LoggedAction &la : this->data->action) { - for (const LoggedChange &lc : la.change) { - switch (lc.ct) { + for (const auto &lc : la.change) { + switch (lc->ct) { default: break; - case GLCT_REVISION: - *last_ottd_rev = lc.revision.newgrf; - *ever_modified = std::max(*ever_modified, lc.revision.modified); + case GLCT_REVISION: { + const LoggedChangeRevision *rev = static_cast(lc.get()); + *last_ottd_rev = rev->newgrf; + *ever_modified = std::max(*ever_modified, rev->modified); break; + } case GLCT_GRFREM: *removed_newgrfs = true; @@ -780,8 +713,11 @@ const GRFIdentifier *Gamelog::GetOverriddenIdentifier(const GRFConfig *c) const LoggedAction &la = this->data->action.back(); if (la.at != GLAT_LOAD) return &c->ident; - for (const LoggedChange &lc : la.change) { - if (lc.ct == GLCT_GRFCOMPAT && lc.grfcompat.grfid == c->ident.grfid) return &lc.grfcompat; + for (const auto &lc : la.change) { + if (lc->ct != GLCT_GRFCOMPAT) continue; + + const LoggedChangeGRFChanged *grf = static_cast(lc.get()); + if (grf->grfid == c->ident.grfid) return grf; } return &c->ident; diff --git a/src/gamelog.h b/src/gamelog.h index 8505c0a170..653a0fec4d 100644 --- a/src/gamelog.h +++ b/src/gamelog.h @@ -52,7 +52,7 @@ private: GamelogActionType action_type; struct LoggedAction *current_action; - LoggedChange *Change(GamelogChangeType ct); + void Change(std::unique_ptr &&change); public: Gamelog(); diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h index 7fc196093e..f1e4b7fb59 100644 --- a/src/gamelog_internal.h +++ b/src/gamelog_internal.h @@ -11,60 +11,139 @@ #define GAMELOG_INTERNAL_H #include "gamelog.h" +#include -static const uint GAMELOG_REVISION_LENGTH = 15; +/** + * Information about the presence of a Grf at a certain point during gamelog history + * Note about missing Grfs: + * Changes to missing Grfs are not logged including manual removal of the Grf. + * So if the gamelog tells a Grf is missing we do not know whether it was readded or completely removed + * at some later point. + */ +struct GRFPresence{ + const GRFConfig *gc; ///< GRFConfig, if known + bool was_missing; ///< Grf was missing during some gameload in the past + + GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {} + GRFPresence() = default; +}; +typedef SmallMap GrfIDMapping; -/** Contains information about one logged change */ struct LoggedChange { - GamelogChangeType ct; ///< Type of change logged in this struct - union { - struct { - byte mode; ///< new game mode - Editor x Game - byte landscape; ///< landscape (temperate, arctic, ...) - } mode; - struct { - char text[GAMELOG_REVISION_LENGTH]; ///< revision string, _openttd_revision - uint32 newgrf; ///< _openttd_newgrf_version - uint16 slver; ///< _sl_version - byte modified; ///< _openttd_revision_modified - } revision; - struct { - uint32 type; ///< type of savegame, @see SavegameType - uint32 version; ///< major and minor version OR ttdp version - } oldver; - GRFIdentifier grfadd; ///< ID and md5sum of added GRF - struct { - uint32 grfid; ///< ID of removed GRF - } grfrem; - GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF - struct { - uint32 grfid; ///< ID of GRF with changed parameters - } grfparam; - struct { - uint32 grfid; ///< ID of moved GRF - int32 offset; ///< offset, positive = move down - } grfmove; - struct { - char *name; ///< name of the setting - int32 oldval; ///< old value - int32 newval; ///< new value - } setting; - struct { - uint64 data; ///< additional data - uint32 grfid; ///< ID of problematic GRF - byte bug; ///< type of bug, @see enum GRFBugs - } grfbug; - }; - - ~LoggedChange(); + LoggedChange(GamelogChangeType type = GLCT_NONE) : ct(type) {} + virtual ~LoggedChange() {} + virtual void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) = 0; + + GamelogChangeType ct; +}; + +struct LoggedChangeMode : LoggedChange { + LoggedChangeMode() : LoggedChange(GLCT_MODE) {} + LoggedChangeMode(byte mode, byte landscape) : + LoggedChange(GLCT_MODE), mode(mode), landscape(landscape) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + byte mode; ///< new game mode - Editor x Game + byte landscape; ///< landscape (temperate, arctic, ...) +}; + +struct LoggedChangeRevision : LoggedChange { + LoggedChangeRevision() : LoggedChange(GLCT_REVISION) {} + LoggedChangeRevision(const std::string &text, uint32_t newgrf, uint16_t slver, byte modified) : + LoggedChange(GLCT_REVISION), text(text), newgrf(newgrf), slver(slver), modified(modified) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + std::string text; ///< revision string, _openttd_revision + uint32_t newgrf; ///< _openttd_newgrf_version + uint16_t slver; ///< _sl_version + byte modified; //< _openttd_revision_modified +}; + +struct LoggedChangeOldVersion : LoggedChange { + LoggedChangeOldVersion() : LoggedChange(GLCT_OLDVER) {} + LoggedChangeOldVersion(uint32_t type, uint32_t version) : + LoggedChange(GLCT_OLDVER), type(type), version(version) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + uint32_t type; ///< type of savegame, @see SavegameType + uint32_t version; ///< major and minor version OR ttdp version +}; + +struct LoggedChangeGRFAdd : LoggedChange, GRFIdentifier { + LoggedChangeGRFAdd() : LoggedChange(GLCT_GRFADD) {} + LoggedChangeGRFAdd(const GRFIdentifier &ident) : + LoggedChange(GLCT_GRFADD), GRFIdentifier(ident) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; +}; + +struct LoggedChangeGRFRemoved : LoggedChange { + LoggedChangeGRFRemoved() : LoggedChange(GLCT_GRFREM) {} + LoggedChangeGRFRemoved(uint32_t grfid) : + LoggedChange(GLCT_GRFREM), grfid(grfid) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + uint32_t grfid; ///< ID of removed GRF +}; + +struct LoggedChangeGRFChanged : LoggedChange, GRFIdentifier { + LoggedChangeGRFChanged() : LoggedChange(GLCT_GRFCOMPAT) {} + LoggedChangeGRFChanged(const GRFIdentifier &ident) : + LoggedChange(GLCT_GRFCOMPAT), GRFIdentifier(ident) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; +}; + +struct LoggedChangeGRFParameterChanged : LoggedChange { + LoggedChangeGRFParameterChanged() : LoggedChange(GLCT_GRFPARAM) {} + LoggedChangeGRFParameterChanged(uint32_t grfid) : + LoggedChange(GLCT_GRFPARAM), grfid(grfid) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + uint32_t grfid; ///< ID of GRF with changed parameters +}; + +struct LoggedChangeGRFMoved : LoggedChange { + LoggedChangeGRFMoved() : LoggedChange(GLCT_GRFMOVE) {} + LoggedChangeGRFMoved(uint32_t grfid, int32_t offset) : + LoggedChange(GLCT_GRFMOVE), grfid(grfid), offset(offset) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + uint32_t grfid; ///< ID of moved GRF + int32_t offset; ///< offset, positive = move down +}; + +struct LoggedChangeSettingChanged : LoggedChange { + LoggedChangeSettingChanged() : LoggedChange(GLCT_SETTING) {} + LoggedChangeSettingChanged(const std::string &name, int32_t oldval, int32_t newval) : + LoggedChange(GLCT_SETTING), name(name), oldval(oldval), newval(newval) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + std::string name; ///< name of the setting + int32_t oldval; ///< old value + int32_t newval; ///< new value +}; + +struct LoggedChangeGRFBug : LoggedChange { + LoggedChangeGRFBug() : LoggedChange(GLCT_GRFBUG) {} + LoggedChangeGRFBug(uint64_t data, uint32_t grfid, byte bug) : + LoggedChange(GLCT_GRFBUG), data(data), grfid(grfid), bug(bug) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; + + uint64_t data; ///< additional data + uint32_t grfid; ///< ID of problematic GRF + byte bug; ///< type of bug, @see enum GRFBugs +}; + +struct LoggedChangeEmergencySave : LoggedChange { + LoggedChangeEmergencySave() : LoggedChange(GLCT_EMERGENCY) {} + void FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) override; }; /** Contains information about one logged action that caused at least one logged change */ struct LoggedAction { - std::vector change; ///< First logged change in this action + std::vector> change; ///< Logged changes in this action GamelogActionType at; ///< Type of action - uint64 tick; ///< Tick when it happened + uint64_t tick; ///< Tick when it happened }; struct GamelogInternalData { diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 43f7d7b32d..0033f83ef4 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -14,6 +14,7 @@ #include "../gamelog_internal.h" #include "../fios.h" +#include "../string_func.h" #include "../safeguards.h" @@ -21,8 +22,8 @@ class SlGamelogMode : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), - SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), + SLE_VARNAME(LoggedChangeMode, mode, "mode.mode", SLE_UINT8), + SLE_VARNAME(LoggedChangeMode, landscape, "mode.landscape", SLE_UINT8), }; inline const static SaveLoadCompatTable compat_description = _gamelog_mode_sl_compat; @@ -43,11 +44,15 @@ public: class SlGamelogRevision : public DefaultSaveLoadHandler { public: + static const size_t GAMELOG_REVISION_LENGTH = 15; + static char revision_text[GAMELOG_REVISION_LENGTH]; + inline static const SaveLoad description[] = { - SLE_ARR(LoggedChange, revision.text, SLE_UINT8, GAMELOG_REVISION_LENGTH), - SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), - SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), - SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), + SLEG_CONDARR("revision.text", SlGamelogRevision::revision_text, SLE_UINT8, GAMELOG_REVISION_LENGTH, SL_MIN_VERSION, SLV_STRING_GAMELOG), + SLE_CONDSSTRNAME(LoggedChangeRevision, text, "revision.text", SLE_STR, SLV_STRING_GAMELOG, SL_MAX_VERSION), + SLE_VARNAME(LoggedChangeRevision, newgrf, "revision.newgrf", SLE_UINT32), + SLE_VARNAME(LoggedChangeRevision, slver, "revision.slver", SLE_UINT16), + SLE_VARNAME(LoggedChangeRevision, modified, "revision.modified", SLE_UINT8), }; inline const static SaveLoadCompatTable compat_description = _gamelog_revision_sl_compat; @@ -61,16 +66,23 @@ public: { if (lc->ct != GLCT_REVISION) return; SlObject(lc, this->GetLoadDescription()); + + if (IsSavegameVersionBefore(SLV_STRING_GAMELOG)) { + StrMakeValidInPlace(SlGamelogRevision::revision_text, lastof(SlGamelogRevision::revision_text)); + static_cast(lc)->text = SlGamelogRevision::revision_text; + } } void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } }; +/* static */ char SlGamelogRevision::revision_text[GAMELOG_REVISION_LENGTH]; + class SlGamelogOldver : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), - SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), + SLE_VARNAME(LoggedChangeOldVersion, type, "oldver.type", SLE_UINT32), + SLE_VARNAME(LoggedChangeOldVersion, version, "oldver.version", SLE_UINT32), }; inline const static SaveLoadCompatTable compat_description = _gamelog_oldver_sl_compat; @@ -92,9 +104,9 @@ public: class SlGamelogSetting : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_STR(LoggedChange, setting.name, SLE_STR, 128), - SLE_VAR(LoggedChange, setting.oldval, SLE_INT32), - SLE_VAR(LoggedChange, setting.newval, SLE_INT32), + SLE_SSTRNAME(LoggedChangeSettingChanged, name, "setting.name", SLE_STR), + SLE_VARNAME(LoggedChangeSettingChanged, oldval, "setting.oldval", SLE_INT32), + SLE_VARNAME(LoggedChangeSettingChanged, newval, "setting.newval", SLE_INT32), }; inline const static SaveLoadCompatTable compat_description = _gamelog_setting_sl_compat; @@ -116,8 +128,8 @@ public: class SlGamelogGrfadd : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), + SLE_VARNAME(LoggedChangeGRFAdd, grfid, "grfadd.grfid", SLE_UINT32 ), + SLE_ARRNAME(LoggedChangeGRFAdd, md5sum, "grfadd.md5sum", SLE_UINT8, 16), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfadd_sl_compat; @@ -139,7 +151,7 @@ public: class SlGamelogGrfrem : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), + SLE_VARNAME(LoggedChangeGRFRemoved, grfid, "grfrem.grfid", SLE_UINT32), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfrem_sl_compat; @@ -161,8 +173,8 @@ public: class SlGamelogGrfcompat : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), - SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), + SLE_VARNAME(LoggedChangeGRFChanged, grfid, "grfcompat.grfid", SLE_UINT32 ), + SLE_ARRNAME(LoggedChangeGRFChanged, md5sum, "grfcompat.md5sum", SLE_UINT8, 16), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfcompat_sl_compat; @@ -184,7 +196,7 @@ public: class SlGamelogGrfparam : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), + SLE_VARNAME(LoggedChangeGRFParameterChanged, grfid, "grfparam.grfid", SLE_UINT32), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfparam_sl_compat; @@ -206,8 +218,8 @@ public: class SlGamelogGrfmove : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), + SLE_VARNAME(LoggedChangeGRFMoved, grfid, "grfmove.grfid", SLE_UINT32), + SLE_VARNAME(LoggedChangeGRFMoved, offset, "grfmove.offset", SLE_INT32), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfmove_sl_compat; @@ -229,9 +241,9 @@ public: class SlGamelogGrfbug : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { - SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), - SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), - SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), + SLE_VARNAME(LoggedChangeGRFBug, data, "grfbug.data", SLE_UINT64), + SLE_VARNAME(LoggedChangeGRFBug, grfid, "grfbug.grfid", SLE_UINT32), + SLE_VARNAME(LoggedChangeGRFBug, bug, "grfbug.bug", SLE_UINT8), }; inline const static SaveLoadCompatTable compat_description = _gamelog_grfbug_sl_compat; @@ -278,6 +290,27 @@ public: void LoadCheck(LoggedChange *lc) const override { this->Load(lc); } }; +static std::unique_ptr MakeLoggedChange(GamelogChangeType type) +{ + switch (type) { + case GLCT_MODE: return std::make_unique(); + case GLCT_REVISION: return std::make_unique(); + case GLCT_OLDVER: return std::make_unique(); + case GLCT_SETTING: return std::make_unique(); + case GLCT_GRFADD: return std::make_unique(); + case GLCT_GRFREM: return std::make_unique(); + case GLCT_GRFCOMPAT: return std::make_unique(); + case GLCT_GRFPARAM: return std::make_unique(); + case GLCT_GRFMOVE: return std::make_unique(); + case GLCT_GRFBUG: return std::make_unique(); + case GLCT_EMERGENCY: return std::make_unique(); + case GLCT_END: + case GLCT_NONE: + default: + SlErrorCorrupt("Invalid gamelog action type"); + } +} + class SlGamelogAction : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { @@ -301,22 +334,25 @@ public: SlSetStructListLength(la->change.size()); for (auto &lc : la->change) { - assert((uint)lc.ct < GLCT_END); - SlObject(&lc, this->GetDescription()); + assert(lc->ct < GLCT_END); + SlObject(lc.get(), this->GetDescription()); } } + void LoadChange(LoggedAction *la, GamelogChangeType type) const + { + std::unique_ptr lc = MakeLoggedChange(type); + SlObject(lc.get(), this->GetLoadDescription()); + la->change.push_back(std::move(lc)); + } + void Load(LoggedAction *la) const override { if (IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY)) { byte type; while ((type = SlReadByte()) != GLCT_NONE) { if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type"); - GamelogChangeType ct = (GamelogChangeType)type; - - LoggedChange &lc = la->change.emplace_back(); - lc.ct = ct; - SlObject(&lc, this->GetLoadDescription()); + LoadChange(la, (GamelogChangeType)type); } return; } @@ -325,9 +361,7 @@ public: la->change.reserve(length); for (size_t i = 0; i < length; i++) { - LoggedChange &lc = la->change.emplace_back(); - lc.ct = (GamelogChangeType)SlReadByte(); - SlObject(&lc, this->GetLoadDescription()); + LoadChange(la, (GamelogChangeType)SlReadByte()); } } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 897e4cf367..ca83816e5a 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -354,6 +354,7 @@ enum SaveLoadVersion : uint16 { SLV_EXTEND_ENTITY_MAPPING, ///< 311 PR#10672 Extend entity mapping range. SLV_DISASTER_VEH_STATE, ///< 312 PR#10798 Explicit storage of disaster vehicle state. SLV_SAVEGAME_ID, ///< 313 PR#10719 Add an unique ID to every savegame (used to deduplicate surveys). + SLV_STRING_GAMELOG, ///< 314 PR#10801 Use std::string in gamelog. SL_MAX_VERSION, ///< Highest possible saveload version }; @@ -771,6 +772,18 @@ struct SaveLoadCompat { */ #define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to, 0) +/** + * Storage of a fixed-size array of #SL_VAR elements in some savegame versions. + * @param base Name of the class or struct containing the array. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the array. + * @param from First savegame version that has the array. + * @param to Last savegame version that has the array. + */ +#define SLE_CONDARRNAME(base, variable, name, type, length, from, to) SLE_GENERAL_NAME(SL_ARR, name, base, variable, type, length, from, to, 0) + /** * Storage of a string in some savegame versions. * @param base Name of the class or struct containing the string. @@ -792,6 +805,17 @@ struct SaveLoadCompat { */ #define SLE_CONDSSTR(base, variable, type, from, to) SLE_GENERAL(SL_STDSTR, base, variable, type, 0, from, to, 0) +/** + * Storage of a \c std::string in some savegame versions. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the string. + * @param to Last savegame version that has the string. + */ +#define SLE_CONDSSTRNAME(base, variable, name, type, from, to) SLE_GENERAL_NAME(SL_STDSTR, name, base, variable, type, 0, from, to, 0) + /** * Storage of a list of #SL_REF elements in some savegame versions. * @param base Name of the class or struct containing the list. @@ -820,6 +844,15 @@ struct SaveLoadCompat { */ #define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of a variable in every version of a savegame. + * @param base Name of the class or struct containing the variable. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_VARNAME(base, variable, name, type) SLE_CONDVARNAME(base, variable, name, type, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Storage of a reference in every version of a savegame. * @param base Name of the class or struct containing the variable. @@ -837,6 +870,16 @@ struct SaveLoadCompat { */ #define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of fixed-size array of #SL_VAR elements in every version of a savegame. + * @param base Name of the class or struct containing the array. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + * @param length Number of elements in the array. + */ +#define SLE_ARRNAME(base, variable, name, type, length) SLE_CONDARRNAME(base, variable, name, type, length, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Storage of a string in every savegame version. * @param base Name of the class or struct containing the string. @@ -854,6 +897,15 @@ struct SaveLoadCompat { */ #define SLE_SSTR(base, variable, type) SLE_CONDSSTR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +/** + * Storage of a \c std::string in every savegame version. + * @param base Name of the class or struct containing the string. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + */ +#define SLE_SSTRNAME(base, variable, name, type) SLE_CONDSSTRNAME(base, variable, name, type, SL_MIN_VERSION, SL_MAX_VERSION) + /** * Storage of a list of #SL_REF elements in every savegame version. * @param base Name of the class or struct containing the list. From e9c03f0dade4dc44c70f9c44655c6115a38a0101 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 10 May 2023 07:19:54 +0200 Subject: [PATCH 49/58] Cleanup: remnants of C-style strings in saveload --- src/saveload/saveload.cpp | 137 +------------------------------------- src/saveload/saveload.h | 32 --------- 2 files changed, 1 insertion(+), 168 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 7221b7d779..dfde9e911f 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -565,7 +565,6 @@ static uint8 GetSavegameFileType(const SaveLoad &sld) case SL_VAR: return GetVarFileType(sld.conv); break; - case SL_STR: case SL_STDSTR: case SL_ARR: case SL_VECTOR: @@ -600,7 +599,6 @@ static inline uint SlCalcConvMemLen(VarType conv) static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0}; switch (GetVarMemType(conv)) { - case SLE_VAR_STRB: case SLE_VAR_STR: case SLE_VAR_STRQ: return SlReadArrayLength(); @@ -878,52 +876,6 @@ static void SlSaveLoadConv(void *ptr, VarType conv) } } -/** - * Calculate the net length of a string. This is in almost all cases - * just strlen(), but if the string is not properly terminated, we'll - * resort to the maximum length of the buffer. - * @param ptr pointer to the stringbuffer - * @param length maximum length of the string (buffer). If -1 we don't care - * about a maximum length, but take string length as it is. - * @return return the net length of the string - */ -static inline size_t SlCalcNetStringLen(const char *ptr, size_t length) -{ - if (ptr == nullptr) return 0; - return std::min(strlen(ptr), length - 1); -} - -/** - * Calculate the gross length of the string that it - * will occupy in the savegame. This includes the real length, returned - * by SlCalcNetStringLen and the length that the index will occupy. - * @param ptr pointer to the stringbuffer - * @param length maximum length of the string (buffer size, etc.) - * @param conv type of data been used - * @return return the gross length of the string - */ -static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv) -{ - size_t len; - const char *str; - - switch (GetVarMemType(conv)) { - default: NOT_REACHED(); - case SLE_VAR_STR: - case SLE_VAR_STRQ: - str = *(const char * const *)ptr; - len = SIZE_MAX; - break; - case SLE_VAR_STRB: - str = (const char *)ptr; - len = length; - break; - } - - len = SlCalcNetStringLen(str, len); - return len + SlGetArrayLength(len); // also include the length of the index -} - /** * Calculate the gross length of the string that it * will occupy in the savegame. This includes the real length, returned @@ -939,86 +891,6 @@ static inline size_t SlCalcStdStringLen(const void *ptr) return len + SlGetArrayLength(len); // also include the length of the index } -/** - * Save/Load a string. - * @param ptr the string being manipulated - * @param length of the string (full length) - * @param conv must be SLE_FILE_STRING - */ -static void SlString(void *ptr, size_t length, VarType conv) -{ - switch (_sl.action) { - case SLA_SAVE: { - size_t len; - switch (GetVarMemType(conv)) { - default: NOT_REACHED(); - case SLE_VAR_STRB: - len = SlCalcNetStringLen((char *)ptr, length); - break; - case SLE_VAR_STR: - case SLE_VAR_STRQ: - ptr = *(char **)ptr; - len = SlCalcNetStringLen((char *)ptr, SIZE_MAX); - break; - } - - SlWriteArrayLength(len); - SlCopyBytes(ptr, len); - break; - } - case SLA_LOAD_CHECK: - case SLA_LOAD: { - size_t len = SlReadArrayLength(); - - switch (GetVarMemType(conv)) { - default: NOT_REACHED(); - case SLE_VAR_NULL: - SlSkipBytes(len); - return; - case SLE_VAR_STRB: - if (len >= length) { - Debug(sl, 1, "String length in savegame is bigger than buffer, truncating"); - SlCopyBytes(ptr, length); - SlSkipBytes(len - length); - len = length - 1; - } else { - SlCopyBytes(ptr, len); - } - break; - case SLE_VAR_STR: - case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate - free(*(char **)ptr); - if (len == 0) { - *(char **)ptr = nullptr; - return; - } else { - *(char **)ptr = MallocT(len + 1); // terminating '\0' - ptr = *(char **)ptr; - SlCopyBytes(ptr, len); - } - break; - } - - ((char *)ptr)[len] = '\0'; // properly terminate the string - StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK; - if ((conv & SLF_ALLOW_CONTROL) != 0) { - settings = settings | SVS_ALLOW_CONTROL_CODE; - if (IsSavegameVersionBefore(SLV_169)) { - str_fix_scc_encoded((char *)ptr, (char *)ptr + len); - } - } - if ((conv & SLF_ALLOW_NEWLINE) != 0) { - settings = settings | SVS_ALLOW_NEWLINE; - } - StrMakeValidInPlace((char *)ptr, (char *)ptr + len, settings); - break; - } - case SLA_PTRS: break; - case SLA_NULL: break; - default: NOT_REACHED(); - } -} - /** * Save/Load a \c std::string. * @param ptr the string being manipulated @@ -1588,7 +1460,6 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) case SL_VAR: return SlCalcConvFileLen(sld.conv); case SL_REF: return SlCalcRefLen(); case SL_ARR: return SlCalcArrayLen(sld.length, sld.conv); - case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld.length, sld.conv); case SL_REFLIST: return SlCalcRefListLen(GetVariableAddress(object, sld), sld.conv); case SL_DEQUE: return SlCalcDequeLen(GetVariableAddress(object, sld), sld.conv); case SL_VECTOR: return SlCalcVectorLen(GetVariableAddress(object, sld), sld.conv); @@ -1660,10 +1531,6 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld) /* These should all be pointer sized. */ return sld.size == sizeof(void *); - case SL_STR: - /* These should be pointer sized, or fixed array. */ - return sld.size == sizeof(void *) || sld.size == sld.length; - case SL_STDSTR: /* These should be all pointers to std::string. */ return sld.size == sizeof(std::string); @@ -1684,7 +1551,6 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) case SL_VAR: case SL_REF: case SL_ARR: - case SL_STR: case SL_REFLIST: case SL_DEQUE: case SL_VECTOR: @@ -1695,7 +1561,6 @@ static bool SlObjectMember(void *object, const SaveLoad &sld) case SL_VAR: SlSaveLoadConv(ptr, conv); break; case SL_REF: SlSaveLoadRef(ptr, conv); break; case SL_ARR: SlArray(ptr, sld.length, conv); break; - case SL_STR: SlString(ptr, sld.length, sld.conv); break; case SL_REFLIST: SlRefList(ptr, conv); break; case SL_DEQUE: SlDeque(ptr, conv); break; case SL_VECTOR: SlVector(ptr, conv); break; @@ -1902,7 +1767,7 @@ std::vector SlTableHeader(const SaveLoadTable &slt) switch (type & SLE_FILE_TYPE_MASK) { case SLE_FILE_STRING: /* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */ - saveload_type = SL_STR; + saveload_type = SL_STDSTR; break; case SLE_FILE_STRUCT: diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index ca83816e5a..3b7627ef73 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -610,7 +610,6 @@ enum VarTypes { SLE_VAR_I64 = 7 << 4, SLE_VAR_U64 = 8 << 4, SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame. - SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer) SLE_VAR_STR = 12 << 4, ///< string pointer SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a char pointer @@ -633,7 +632,6 @@ enum VarTypes { SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR, SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U32, - SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB, SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR, SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ, SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME, @@ -641,7 +639,6 @@ enum VarTypes { /* Shortcut values */ SLE_UINT = SLE_UINT32, SLE_INT = SLE_INT32, - SLE_STRB = SLE_STRINGBUF, SLE_STR = SLE_STRING, SLE_STRQ = SLE_STRINGQUOTE, @@ -659,7 +656,6 @@ enum SaveLoadType : byte { SL_REF = 1, ///< Save/load a reference. SL_STRUCT = 2, ///< Save/load a struct. - SL_STR = 3, ///< Save/load a string. SL_STDSTR = 4, ///< Save/load a \c std::string. SL_ARR = 5, ///< Save/load a fixed-size array of #SL_VAR elements. @@ -880,15 +876,6 @@ struct SaveLoadCompat { */ #define SLE_ARRNAME(base, variable, name, type, length) SLE_CONDARRNAME(base, variable, name, type, length, SL_MIN_VERSION, SL_MAX_VERSION) -/** - * Storage of a string in every savegame version. - * @param base Name of the class or struct containing the string. - * @param variable Name of the variable in the class or struct referenced by \a base. - * @param type Storage of the data in memory and in the savegame. - * @param length Number of elements in the string (only used for fixed size buffers). - */ -#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, SL_MIN_VERSION, SL_MAX_VERSION) - /** * Storage of a \c std::string in every savegame version. * @param base Name of the class or struct containing the string. @@ -970,17 +957,6 @@ struct SaveLoadCompat { */ #define SLEG_CONDARR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_ARR, variable, type, length, from, to, 0) -/** - * Storage of a global string in some savegame versions. - * @param name The name of the field. - * @param variable Name of the global variable. - * @param type Storage of the data in memory and in the savegame. - * @param length Number of elements in the string (only used for fixed size buffers). - * @param from First savegame version that has the string. - * @param to Last savegame version that has the string. - */ -#define SLEG_CONDSTR(name, variable, type, length, from, to) SLEG_GENERAL(name, SL_STR, variable, type, length, from, to, 0) - /** * Storage of a global \c std::string in some savegame versions. * @param name The name of the field. @@ -1053,14 +1029,6 @@ struct SaveLoadCompat { */ #define SLEG_ARR(name, variable, type) SLEG_CONDARR(name, variable, type, lengthof(variable), SL_MIN_VERSION, SL_MAX_VERSION) -/** - * Storage of a global string in every savegame version. - * @param name The name of the field. - * @param variable Name of the global variable. - * @param type Storage of the data in memory and in the savegame. - */ -#define SLEG_STR(name, variable, type) SLEG_CONDSTR(name, variable, type, sizeof(variable), SL_MIN_VERSION, SL_MAX_VERSION) - /** * Storage of a global \c std::string in every savegame version. * @param name The name of the field. From a5cf36288642e288ea88f7b10c8ddb08d1351844 Mon Sep 17 00:00:00 2001 From: translators Date: Tue, 16 May 2023 18:41:59 +0000 Subject: [PATCH 50/58] Update: Translations from eints english (au): 14 changes by krysclarke english (us): 14 changes by 2TallTyler vietnamese: 14 changes by KhoiCanDev korean: 19 changes by telk5093 italian: 14 changes by Rivarossi russian: 14 changes by Ln-Wolf finnish: 14 changes by hpiirai danish: 22 changes by bscargo portuguese: 14 changes by azulcosta polish: 14 changes by pAter-exe --- src/lang/danish.txt | 22 ++++++++++++++++++++++ src/lang/english_AU.txt | 14 ++++++++++++++ src/lang/english_US.txt | 14 ++++++++++++++ src/lang/finnish.txt | 14 ++++++++++++++ src/lang/italian.txt | 14 ++++++++++++++ src/lang/korean.txt | 21 +++++++++++++++++++-- src/lang/polish.txt | 14 ++++++++++++++ src/lang/portuguese.txt | 14 ++++++++++++++ src/lang/russian.txt | 14 ++++++++++++++ src/lang/vietnamese.txt | 14 ++++++++++++++ 10 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/lang/danish.txt b/src/lang/danish.txt index d567e728a8..9c49a44023 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -1041,6 +1041,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automatiseret undersøgelse +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Deltag i automatiseret undersøgelse +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Når det er aktiveret, sender OpenTTD en undersøgelse, når du forlader et spil +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :Om GPDR og privatliv +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Dette åbner en browser med mere information om den automatiserede undersøgelse +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Forhåndsvisning af undersøgelsesresultat +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Vis undersøgelsesresultatet af det aktuelle spil STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik @@ -1171,6 +1178,7 @@ STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Udvid al STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Skjul alle STR_CONFIG_SETTING_RESET_ALL :{BLACK}Nulstil alle værdier STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(ingen forklaring tilgængelig) +STR_CONFIG_SETTING_VALUE :{PUSH_COLOUR}{ORANGE}{STRING}{POP_COLOUR} STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standard: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Indstillingstype: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Klient indstilling (ikke lagret i gemt spil, påvirker alle spil) @@ -2402,6 +2410,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nej STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Ja, denne gang STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Ja, spørg ikke igen +STR_NETWORK_ASK_SURVEY_CAPTION :Deltag i automatiseret undersøgelse? +STR_NETWORK_ASK_SURVEY_TEXT :Kunne du tænke dig at deltage i den automatiske undersøgelse?{}OpenTTD sender en undersøgelse, når du forlader et spil.{}Du kan til enhver tid ændre dette under "Spilindstillinger". +STR_NETWORK_ASK_SURVEY_PREVIEW :Forhåndsvisning af undersøgelsesresultat +STR_NETWORK_ASK_SURVEY_LINK :Om undersøgelse og privatliv +STR_NETWORK_ASK_SURVEY_NO :Nej +STR_NETWORK_ASK_SURVEY_YES :Ja STR_NETWORK_SPECTATORS :Tilskuere @@ -2693,7 +2707,10 @@ STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Vælg hv STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Vælg hvilken stationstype du vil bygge STR_STATION_CLASS_DFLT :Standard station +STR_STATION_CLASS_DFLT_STATION :Standard station +STR_STATION_CLASS_DFLT_ROADSTOP :Standard vejstop STR_STATION_CLASS_WAYP :Rutepunkt +STR_STATION_CLASS_WAYP_WAYPOINT :Standard rutepunkt # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Signalvælger @@ -3829,6 +3846,8 @@ STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Send ins STR_VEHICLE_LIST_REPLACE_VEHICLES :Udskift køretøjer STR_VEHICLE_LIST_SEND_FOR_SERVICING :Send til eftersyn STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Afkast i år: {CURRENCY_LONG} (sidste år: {CURRENCY_LONG}) +STR_VEHICLE_LIST_CARGO :[{CARGO_LIST}] +STR_VEHICLE_LIST_NAME_AND_CARGO :{STRING} {STRING} STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Send til remise STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Send til værksted @@ -4654,6 +4673,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licens STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme for {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} ændringslog for {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licens for {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :Forhåndsvisning af undersøgelsesresultat # Vehicle loading indicators @@ -5590,11 +5610,13 @@ STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} +STR_JUST_RIGHT_ARROW :{RIGHT_ARROW} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} +STR_JUST_DECIMAL :{DECIMAL} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index a8c4bcc1bd..c5ff3f9ee3 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -1041,6 +1041,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Participate in automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}When enabled, OpenTTD will transmit a survey when leaving a game +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}About survey and privacy +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}This opens a browser with more information about the automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Preview survey result +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Show the survey result of the current running game STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphics @@ -2403,6 +2410,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Yes, this once STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Yes, don't ask again +STR_NETWORK_ASK_SURVEY_CAPTION :Participate in automated survey? +STR_NETWORK_ASK_SURVEY_TEXT :Would you like to participate in the automated survey?{}OpenTTD will transmit a survey when leaving a game.{}You can change this at any time under "Game Options". +STR_NETWORK_ASK_SURVEY_PREVIEW :Preview survey result +STR_NETWORK_ASK_SURVEY_LINK :About survey and privacy +STR_NETWORK_ASK_SURVEY_NO :No +STR_NETWORK_ASK_SURVEY_YES :Yes STR_NETWORK_SPECTATORS :Spectators @@ -4660,6 +4673,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}License STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} license of {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Preview of survey result # Vehicle loading indicators diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index f1a0705ed1..0d8a3d1661 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -1041,6 +1041,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Participate in automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}When enabled, OpenTTD will transmit a survey when leaving a game +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}About survey and privacy +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}This opens a browser with more information about the automated survey +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Preview survey result +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Show the survey result of the current running game STR_GAME_OPTIONS_GRAPHICS :{BLACK}Graphics @@ -2403,6 +2410,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Yes, this once STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Yes, don't ask again +STR_NETWORK_ASK_SURVEY_CAPTION :Participate in automated survey? +STR_NETWORK_ASK_SURVEY_TEXT :Would you like to participate in the automated survey?{}OpenTTD will transmit a survey when leaving a game.{}You can change this at any time under "Game Options". +STR_NETWORK_ASK_SURVEY_PREVIEW :Preview survey result +STR_NETWORK_ASK_SURVEY_LINK :About survey and privacy +STR_NETWORK_ASK_SURVEY_NO :No +STR_NETWORK_ASK_SURVEY_YES :Yes STR_NETWORK_SPECTATORS :Spectators @@ -4660,6 +4673,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}License STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} license of {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Preview of survey result # Vehicle loading indicators diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index da20e95673..691ca6436b 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -1041,6 +1041,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3× STR_GAME_OPTIONS_GUI_SCALE_4X :4× STR_GAME_OPTIONS_GUI_SCALE_5X :5× +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automatisoitu tutkimus +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Osallistu automatisoituun tutkimukseen +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Mikäli käytössä, OpenTTD lähettää tilastointitietoja pelistä poistuttaessa +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}Tutkimuksesta ja yksityisyydestä +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Avaa selaimen, jossa lisätietoja automatisoidusta tutkimuksesta +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Esikatsele tutkimustulosta +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Näytä meneillään olevan pelin tutkimustulos STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafiikka @@ -2403,6 +2410,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Ei STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Kyllä, tämän kerran STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Kyllä, älä kysy uudestaan +STR_NETWORK_ASK_SURVEY_CAPTION :Osallistutko automatisoituun tutkimukseen? +STR_NETWORK_ASK_SURVEY_TEXT :Haluatko osallistua automatisoituun tutkimukseen?{}Tällöin OpenTTD lähettää tilastointitietoja aina pelistä poistuttaessa.{}Voit muuttaa tätä milloin tahansa kohdassa ”Pelin asetukset”. +STR_NETWORK_ASK_SURVEY_PREVIEW :Esikatsele tutkimustulosta +STR_NETWORK_ASK_SURVEY_LINK :Tutkimuksesta ja yksityisyydestä +STR_NETWORK_ASK_SURVEY_NO :En +STR_NETWORK_ASK_SURVEY_YES :Osallistun STR_NETWORK_SPECTATORS :Katsojat @@ -4660,6 +4673,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisenssi STR_TEXTFILE_README_CAPTION :{WHITE}{STRING}:n {STRING} readme-tiedosto STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING}:n {STRING} muutosloki STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING}:n {STRING} lisenssi +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Tutkimustuloksen esikatselu # Vehicle loading indicators diff --git a/src/lang/italian.txt b/src/lang/italian.txt index fa90c2747e..fc443875d7 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -1043,6 +1043,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Sondaggio automatizzato +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Partecipare al sondaggio automatico +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Se abilitato, OpenTTD trasmette un sondaggio quando si lascia una partita. +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}Informazioni sul sondaggio e sulla privacy +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Apre un browser con ulteriori informazioni sul sondaggio automatico. +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Anteprima del risultato del sondaggio +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Mostra il risultato del sondaggio della partita in corso STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafica @@ -2438,6 +2445,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}No STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sì, questa volta STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sì, non chiederlo più +STR_NETWORK_ASK_SURVEY_CAPTION :Partecipare a un sondaggio automatico? +STR_NETWORK_ASK_SURVEY_TEXT :Desideri partecipare al sondaggio automatizzato?{}OpenTTD trasmette un sondaggio quando si lascia una partita.{}Puoi cambiare questa impostazione in qualsiasi momento sotto "Opzioni di gioco". +STR_NETWORK_ASK_SURVEY_PREVIEW :Anteprima del risultato del sondaggio +STR_NETWORK_ASK_SURVEY_LINK :Informazioni sul sondaggio e sulla privacy +STR_NETWORK_ASK_SURVEY_NO :No +STR_NETWORK_ASK_SURVEY_YES :Sì STR_NETWORK_SPECTATORS :Spettatori @@ -4701,6 +4714,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenza STR_TEXTFILE_README_CAPTION :{WHITE}File leggimi del {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Changelog del {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licenza del {STRING} {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Anteprima del risultato del sondaggio # Vehicle loading indicators diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 4894f35a06..fd253d837d 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -930,7 +930,7 @@ STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}이 장 STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}외부 화면에 저장된 장소로 이동합니다. # Game options window -STR_GAME_OPTIONS_CAPTION :{WHITE}게임 기본 설정 +STR_GAME_OPTIONS_CAPTION :{WHITE}게임 설정 STR_GAME_OPTIONS_TAB_GENERAL :일반 STR_GAME_OPTIONS_TAB_GENERAL_TT :{BLACK}일반 설정을 선택합니다 @@ -1042,6 +1042,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}자동 설문 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}자동 설문조사 참여 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}이 설정을 켜면, 게임을 종료할 때마다 OpenTTD가 관련 설문 통계를 전송합니다 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}설문조사와 개인정보 보호에 대하여 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}자동 설문조사에 대한 더 많은 정보를 보여주기 위해 브라우저 창을 엽니다 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}설문조사 결과 미리보기 +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}현재 진행 중인 게임의 설문조사 결과를 보여줍니다 STR_GAME_OPTIONS_GRAPHICS :{BLACK}그래픽 @@ -2404,6 +2411,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}아니 STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}이번에만 사용 STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}항상 사용 +STR_NETWORK_ASK_SURVEY_CAPTION :설문조사에 참여하시겠습니까? +STR_NETWORK_ASK_SURVEY_TEXT :자동 설문조사에 참여하시겠습니까?{}게임을 종료할 때마다 OpenTTD가 관련 설문 통계를 전송합니다.{}"게임 설정"에서 참여 여부를 변경할 수 있습니다. +STR_NETWORK_ASK_SURVEY_PREVIEW :설문조사 결과 미리보기 +STR_NETWORK_ASK_SURVEY_LINK :설문조사와 개인정보 보호에 대하여 +STR_NETWORK_ASK_SURVEY_NO :아니요 +STR_NETWORK_ASK_SURVEY_YES :예 STR_NETWORK_SPECTATORS :관전자 @@ -2694,8 +2707,11 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}드래 STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}표시할 역의 종류를 선택합니다 STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}건설할 역의 종류를 선택합니다 -STR_STATION_CLASS_DFLT :기본 역사 +STR_STATION_CLASS_DFLT :기본 +STR_STATION_CLASS_DFLT_STATION :기본 역 +STR_STATION_CLASS_DFLT_ROADSTOP :기본 도로 정류장 STR_STATION_CLASS_WAYP :경유지 +STR_STATION_CLASS_WAYP_WAYPOINT :기본 경유지 # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}신호기 선택 @@ -4658,6 +4674,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}저작 STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING}의 Readme STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING}의 변경기록 STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING}의 저작권 +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}설문조사 결과 미리보기 # Vehicle loading indicators diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 98cea5f7b9..543ef3b946 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1421,6 +1421,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Automatyczna ankieta +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Udział w automatycznej ankiecie +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Kiedy włączone, OpenTTD prześle ankietę przy opuszczaniu gry +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}O ankiecie i prywatności +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Spowoduje to otwarcie przeglądarki z dodatkowymi informacjami na temat automatycznej ankiety +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Podejrzyj wynik ankiety +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Pokaż wynik ankiety dotyczącej bieżącej gry STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafika @@ -2783,6 +2790,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Nie STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Tak, ten jeden raz STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Tak, nie pytaj ponownie +STR_NETWORK_ASK_SURVEY_CAPTION :Uczestniczyć w automatycznej ankiecie? +STR_NETWORK_ASK_SURVEY_TEXT :Czy chcesz wziąć udział w automatycznej ankiecie?{}OpenTTD prześle ankietę przy opuszczaniu gry.{}Możesz to zmienić w dowolnym momencie w „Opcjach gry”. +STR_NETWORK_ASK_SURVEY_PREVIEW :Podejrzyj wynik ankiety +STR_NETWORK_ASK_SURVEY_LINK :O ankiecie i prywatności +STR_NETWORK_ASK_SURVEY_NO :Nie +STR_NETWORK_ASK_SURVEY_YES :Tak STR_NETWORK_SPECTATORS :Widzowie @@ -5046,6 +5059,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licencja STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} {STRING} - plik „readme” STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} {STRING} - lista zmian STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} {STRING} - licencja +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Podgląd wyniku ankiety # Vehicle loading indicators diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 7ec204dac1..822d9c8439 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -1042,6 +1042,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Sondagem automatizada +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Participar numa sondagem automatizada +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Quando ativo, o OpenTTD transmitirá uma sondagem ao deixar um jogo +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}Sobre sondagem e privacidade +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Isto abre um navegador com mais informações sobre a pesquisa automatizada +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Pré-visualizar resultado da sondagem +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Mostrar o resultado da sondagem do jogo atual a decorrer STR_GAME_OPTIONS_GRAPHICS :{BLACK}Gráficos @@ -2404,6 +2411,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Não STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Sim, desta vez STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Sim, não perguntar novamente +STR_NETWORK_ASK_SURVEY_CAPTION :Participar na sondagem automatizada ? +STR_NETWORK_ASK_SURVEY_TEXT :Pretende participar numa sondagem automatizada?{}OpenTTD irá transmitir uma sondagem ao deixar um jogo.{}Pode alterar isto em qualquer altura nas "Opções de Jogo". +STR_NETWORK_ASK_SURVEY_PREVIEW :Pré-visualizar resultado da sondagem +STR_NETWORK_ASK_SURVEY_LINK :Sobre sondagem e privacidade +STR_NETWORK_ASK_SURVEY_NO :Não +STR_NETWORK_ASK_SURVEY_YES :Sim STR_NETWORK_SPECTATORS :Espectadores @@ -4661,6 +4674,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licença STR_TEXTFILE_README_CAPTION :{WHITE}Leiame {STRING} de {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Lista de alterações {STRING} de {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Licença {STRING} de {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Pré-visualização do resultado da sondagem # Vehicle loading indicators diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 9dba08aa9e..f509ab640c 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -1186,6 +1186,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Автоматический сбор данных +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Разрешить автоматический сбор данных +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Разрешить автоматический сбор данных о ваших настройках игры и используемых модулях. OpenTTD отправит эти данные при закрытии игры. +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}О сборе данных и приватности +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Открыть ссылку с информацией об автоматическом сборе данных +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Просмотр собранных данных +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Показать собранные в текущем сеансе данные STR_GAME_OPTIONS_GRAPHICS :{BLACK}Настройки графики @@ -2554,6 +2561,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Нет STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Да, однократно STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Да, всегда +STR_NETWORK_ASK_SURVEY_CAPTION :Разрешить автоматический сбор данных? +STR_NETWORK_ASK_SURVEY_TEXT :Разрешаете ли вы автоматический сбор данных о ваших настройках игры и используемых модулях?{}OpenTTD отправит эти данные при закрытии игры.{}Вы можете в любой момент открыть настройки и изменить своё решение. +STR_NETWORK_ASK_SURVEY_PREVIEW :Просмотр собранных данных +STR_NETWORK_ASK_SURVEY_LINK :О сборе данных и приватности +STR_NETWORK_ASK_SURVEY_NO :Нет +STR_NETWORK_ASK_SURVEY_YES :Да STR_NETWORK_SPECTATORS :Зрители @@ -4847,6 +4860,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Лице STR_TEXTFILE_README_CAPTION :{WHITE}Инструкция к {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Список изменений к {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Лицензия к {STRING} {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Собранные данные # Vehicle loading indicators diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 35d2e460cc..258e7a219b 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -1041,6 +1041,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Khảo sát tự động +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Tham gia khảo sát tự động +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Khi bật, OpenTTD sẽ gửi một khảo sát lúc rời ván chơi +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}Về khảo sát và quyền riêng tư +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Sẽ mở trình duyệt để xem thêm thông tin về khảo sát tự động +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Xem trước kết quả khảo sát +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Hiển thị kết quả khảo sát ở ván chơi hiện tại STR_GAME_OPTIONS_GRAPHICS :{BLACK}Hình ảnh @@ -2403,6 +2410,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Không STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Đồng ý, chỉ lần này STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Đồng ý, đừng hỏi lại +STR_NETWORK_ASK_SURVEY_CAPTION :Tham gia khảo sát tự động? +STR_NETWORK_ASK_SURVEY_TEXT :Bạn có muốn tham gia khảo sát tự động?{}OpenTTD sẽ gửi một khảo sát lúc rời ván chơi.{}Bạn có thể thay đổi thiết lập này ở "Thiết lập ván chơi". +STR_NETWORK_ASK_SURVEY_PREVIEW :Xem trước kết quả khảo sát +STR_NETWORK_ASK_SURVEY_LINK :Về khảo sát và quyền riêng tư +STR_NETWORK_ASK_SURVEY_NO :Không +STR_NETWORK_ASK_SURVEY_YES :Có STR_NETWORK_SPECTATORS :Người xem @@ -4660,6 +4673,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Giấy p STR_TEXTFILE_README_CAPTION :{WHITE}Readme của {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Lịch sử thay đổi của {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Giấy phép của {STRING} {STRING} +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Xem trước kết quả khảo sát # Vehicle loading indicators From 56085be9bda8d5682c15544a058d988a6ae00b3b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 May 2023 09:08:39 +0100 Subject: [PATCH 51/58] Codechange: Move includes for common STL headers to stdafx. --- src/ai/ai_info.cpp | 1 - src/blitter/factory.hpp | 1 - src/cargomonitor.h | 1 - src/cargopacket.h | 1 - src/command.cpp | 2 -- src/company_base.h | 1 - src/console_gui.cpp | 1 - src/console_internal.h | 1 - src/core/multimap.hpp | 3 --- src/driver.h | 1 - src/error.h | 1 - src/error_gui.cpp | 1 - src/fileio.cpp | 1 - src/game/game_info.cpp | 1 - src/gamelog_internal.h | 1 - src/gfx_layout.h | 1 - src/gfx_layout_icu.cpp | 2 -- src/industrytype.h | 1 - src/landscape.cpp | 3 --- src/linkgraph/linkgraph_gui.h | 1 - src/linkgraph/linkgraphjob.h | 1 - src/linkgraph/mcf.cpp | 1 - src/linkgraph/refresh.h | 2 -- src/misc/dbg_helpers.h | 1 - src/misc/lrucache.hpp | 1 - src/network/core/tcp.h | 1 - src/network/core/tcp_connect.cpp | 2 -- src/network/network_chat_gui.cpp | 2 -- src/network/network_command.cpp | 1 - src/network/network_coordinator.h | 1 - src/network/network_gui.cpp | 2 -- src/newgrf.cpp | 1 - src/newgrf_generic.cpp | 1 - src/newgrf_gui.cpp | 1 - src/newgrf_storage.cpp | 1 - src/newgrf_text.cpp | 3 --- src/os/macosx/macos.mm | 1 - src/os/windows/win32.cpp | 1 - src/roadveh.h | 1 - src/saveload/map_sl.cpp | 1 - src/saveload/oldloader_sl.cpp | 1 - src/saveload/saveload.cpp | 1 - src/saveload/vehicle_sl.cpp | 2 -- src/script/api/script_controller.hpp | 1 - src/script/api/script_error.hpp | 1 - src/script/api/script_list.hpp | 2 -- src/script/api/script_log_types.hpp | 2 -- src/script/script_config.hpp | 2 -- src/script/script_instance.hpp | 1 - src/script/script_scanner.hpp | 1 - src/script/squirrel.cpp | 1 - src/settings_table.h | 1 - src/ship.h | 2 -- src/station_base.h | 2 -- src/station_gui.cpp | 2 -- src/station_type.h | 1 - src/stdafx.h | 5 +++++ src/tar_type.h | 3 --- src/terraform_cmd.cpp | 3 --- src/tests/landscape_partial_pixel_z.cpp | 1 - src/tests/string_func.cpp | 1 - src/timer/timer_manager.h | 2 -- src/town.h | 1 - src/townname_type.h | 1 - src/vehicle_base.h | 2 -- src/video/cocoa/cocoa_v.mm | 1 - src/video/cocoa/cocoa_wnd.mm | 1 - src/video/opengl.cpp | 1 - src/viewport.cpp | 1 - src/viewport_sprite_sorter_sse4.cpp | 1 - src/widgets/slider_func.h | 2 -- src/window_gui.h | 2 -- 72 files changed, 5 insertions(+), 98 deletions(-) diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index c2757427f5..2b3036c8ef 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -15,7 +15,6 @@ #include "../debug.h" #include "../string_func.h" #include "../rev.h" -#include #include "../safeguards.h" diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp index 554f1e4292..77911fc31c 100644 --- a/src/blitter/factory.hpp +++ b/src/blitter/factory.hpp @@ -13,7 +13,6 @@ #include "base.hpp" #include "../debug.h" #include "../string_func.h" -#include /** diff --git a/src/cargomonitor.h b/src/cargomonitor.h index 31053c46cb..0891bf88b1 100644 --- a/src/cargomonitor.h +++ b/src/cargomonitor.h @@ -15,7 +15,6 @@ #include "industry.h" #include "town.h" #include "core/overflowsafe_type.hpp" -#include struct Station; diff --git a/src/cargopacket.h b/src/cargopacket.h index 9aacfed57c..c4ba7e5cf6 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -18,7 +18,6 @@ #include "vehicle_type.h" #include "core/multimap.hpp" #include "saveload/saveload.h" -#include /** Unique identifier for a single cargo packet. */ typedef uint32 CargoPacketID; diff --git a/src/command.cpp b/src/command.cpp index a8efcebb23..8be2de9872 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -59,8 +59,6 @@ #include "misc/endian_buffer.hpp" #include "string_func.h" -#include - #include "table/strings.h" #include "safeguards.h" diff --git a/src/company_base.h b/src/company_base.h index d41da57f45..dd7521c4a8 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -17,7 +17,6 @@ #include "timer/timer_game_calendar.h" #include "settings_type.h" #include "group.h" -#include /** Statistics about the economy. */ struct CompanyEconomyEntry { diff --git a/src/console_gui.cpp b/src/console_gui.cpp index c9d91b8fe4..1d4e9b29c7 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -22,7 +22,6 @@ #include "video/video_driver.hpp" #include "timer/timer.h" #include "timer/timer_window.h" -#include #include "widgets/console_widget.h" diff --git a/src/console_internal.h b/src/console_internal.h index 80752a08eb..19e798c19e 100644 --- a/src/console_internal.h +++ b/src/console_internal.h @@ -11,7 +11,6 @@ #define CONSOLE_INTERNAL_H #include "gfx_type.h" -#include static const uint ICON_CMDLN_SIZE = 1024; ///< maximum length of a typed in command static const uint ICON_MAX_STREAMSIZE = 2048; ///< maximum length of a totally expanded command diff --git a/src/core/multimap.hpp b/src/core/multimap.hpp index 026488b355..9a646414d1 100644 --- a/src/core/multimap.hpp +++ b/src/core/multimap.hpp @@ -10,9 +10,6 @@ #ifndef MULTIMAP_HPP #define MULTIMAP_HPP -#include -#include - template class MultiMap; diff --git a/src/driver.h b/src/driver.h index 4caf825c88..91287fbdb2 100644 --- a/src/driver.h +++ b/src/driver.h @@ -12,7 +12,6 @@ #include "core/enum_type.hpp" #include "string_type.h" -#include const char *GetDriverParam(const StringList &parm, const char *name); bool GetDriverParamBool(const StringList &parm, const char *name); diff --git a/src/error.h b/src/error.h index cac0c503bf..88ec12e9f6 100644 --- a/src/error.h +++ b/src/error.h @@ -10,7 +10,6 @@ #ifndef ERROR_H #define ERROR_H -#include #include "strings_type.h" #include "company_type.h" #include "command_type.h" diff --git a/src/error_gui.cpp b/src/error_gui.cpp index 6e076940ca..117a9db8ee 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -27,7 +27,6 @@ #include "widgets/error_widget.h" #include "table/strings.h" -#include #include "safeguards.h" diff --git a/src/fileio.cpp b/src/fileio.cpp index f0bef68d7c..92707b58e4 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -25,7 +25,6 @@ #include #endif #include -#include #include #include "safeguards.h" diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp index db3b53e259..f6c9bd952c 100644 --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -13,7 +13,6 @@ #include "game_info.hpp" #include "game_scanner.hpp" #include "../debug.h" -#include #include "../safeguards.h" diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h index f1e4b7fb59..bd8957a54c 100644 --- a/src/gamelog_internal.h +++ b/src/gamelog_internal.h @@ -11,7 +11,6 @@ #define GAMELOG_INTERNAL_H #include "gamelog.h" -#include /** * Information about the presence of a Grf at a certain point during gamelog history diff --git a/src/gfx_layout.h b/src/gfx_layout.h index 645311f1da..f66bebefa0 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -14,7 +14,6 @@ #include "gfx_func.h" #include "core/smallmap_type.hpp" -#include #include #include diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index 12bf5d28b2..730df125bd 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -24,8 +24,6 @@ #include #include -#include - #include "safeguards.h" /** harfbuzz doesn't use floats, so we need a value to scale position with to get sub-pixel precision. */ diff --git a/src/industrytype.h b/src/industrytype.h index 79635baaed..8d151e2100 100644 --- a/src/industrytype.h +++ b/src/industrytype.h @@ -10,7 +10,6 @@ #ifndef INDUSTRYTYPE_H #define INDUSTRYTYPE_H -#include #include "map_type.h" #include "slope_type.h" #include "industry_type.h" diff --git a/src/landscape.cpp b/src/landscape.cpp index 3bced4eef5..b151365858 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -36,9 +36,6 @@ #include "landscape_cmd.h" #include "terraform_cmd.h" #include "station_func.h" -#include -#include -#include #include "table/strings.h" #include "table/sprites.h" diff --git a/src/linkgraph/linkgraph_gui.h b/src/linkgraph/linkgraph_gui.h index 226cd6b265..04f45c96e4 100644 --- a/src/linkgraph/linkgraph_gui.h +++ b/src/linkgraph/linkgraph_gui.h @@ -15,7 +15,6 @@ #include "../widget_type.h" #include "../window_gui.h" #include "linkgraph_base.h" -#include /** * Monthly statistics for a link between two stations. diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index 5d7b8ebef2..2c2e9a86cc 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -12,7 +12,6 @@ #include "../thread.h" #include "linkgraph.h" -#include #include class LinkGraphJob; diff --git a/src/linkgraph/mcf.cpp b/src/linkgraph/mcf.cpp index c7b5d6d075..508e9616b9 100644 --- a/src/linkgraph/mcf.cpp +++ b/src/linkgraph/mcf.cpp @@ -3,7 +3,6 @@ #include "../stdafx.h" #include "../core/math_func.hpp" #include "mcf.h" -#include #include "../safeguards.h" diff --git a/src/linkgraph/refresh.h b/src/linkgraph/refresh.h index 097a3577c6..15a9796e5e 100644 --- a/src/linkgraph/refresh.h +++ b/src/linkgraph/refresh.h @@ -12,8 +12,6 @@ #include "../cargo_type.h" #include "../vehicle_base.h" -#include -#include /** * Utility to refresh links a consist will visit. diff --git a/src/misc/dbg_helpers.h b/src/misc/dbg_helpers.h index a024b9dd2e..5317b77d30 100644 --- a/src/misc/dbg_helpers.h +++ b/src/misc/dbg_helpers.h @@ -10,7 +10,6 @@ #ifndef DBG_HELPERS_H #define DBG_HELPERS_H -#include #include #include "../direction_type.h" diff --git a/src/misc/lrucache.hpp b/src/misc/lrucache.hpp index 2c474c2a84..3adedbefd4 100644 --- a/src/misc/lrucache.hpp +++ b/src/misc/lrucache.hpp @@ -11,7 +11,6 @@ #define LRUCACHE_HPP #include -#include #include /** diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 252f2c2456..0a770d30eb 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -17,7 +17,6 @@ #include #include -#include #include /** The states of sending the packets. */ diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp index 17c1de886f..9e96240774 100644 --- a/src/network/core/tcp_connect.cpp +++ b/src/network/core/tcp_connect.cpp @@ -16,8 +16,6 @@ #include "../network_coordinator.h" #include "../network_internal.h" -#include - #include "../../safeguards.h" /** List of connections that are currently being created */ diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index cf04ebcef9..aadee357e0 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -28,8 +28,6 @@ #include "table/strings.h" -#include - #include "../safeguards.h" /** The draw buffer must be able to contain the chat message, client name and the "[All]" message, diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 06fee00798..30b3bde67a 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -51,7 +51,6 @@ #include "../water_cmd.h" #include "../waypoint_cmd.h" #include "../script/script_cmd.h" -#include #include "../safeguards.h" diff --git a/src/network/network_coordinator.h b/src/network/network_coordinator.h index 3977c4e634..453ee938c5 100644 --- a/src/network/network_coordinator.h +++ b/src/network/network_coordinator.h @@ -13,7 +13,6 @@ #include "core/tcp_coordinator.h" #include "network_stun.h" #include "network_turn.h" -#include /** * Game Coordinator communication. diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 68c00b15b1..0345eefd69 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -52,8 +52,6 @@ # include #endif -#include - #include "../safeguards.h" static void ShowNetworkStartServerWindow(); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index ed619c8a98..a89c47f12b 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -41,7 +41,6 @@ #include "timer/timer_game_calendar.h" #include "string_func.h" #include "network/core/config.h" -#include #include "smallmap_gui.h" #include "genworld.h" #include "error.h" diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index f2e15f68bd..32543a3388 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -14,7 +14,6 @@ #include "core/random_func.hpp" #include "newgrf_sound.h" #include "water_map.h" -#include #include "safeguards.h" diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 2f3e5d2f09..9e8449834f 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -36,7 +36,6 @@ #include "table/sprites.h" -#include #include "safeguards.h" /** diff --git a/src/newgrf_storage.cpp b/src/newgrf_storage.cpp index a0130f829a..d333a939f8 100644 --- a/src/newgrf_storage.cpp +++ b/src/newgrf_storage.cpp @@ -12,7 +12,6 @@ #include "core/pool_func.hpp" #include "core/endian_func.hpp" #include "debug.h" -#include #include "safeguards.h" diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 3fe0d49b51..0e30cde965 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -17,8 +17,6 @@ #include "stdafx.h" -#include - #include "newgrf.h" #include "strings_func.h" #include "newgrf_storage.h" @@ -31,7 +29,6 @@ #include "core/smallmap_type.hpp" #include "language.h" #include -#include #include "table/strings.h" #include "table/control_codes.h" diff --git a/src/os/macosx/macos.mm b/src/os/macosx/macos.mm index 452b151e9c..9db5cd049f 100644 --- a/src/os/macosx/macos.mm +++ b/src/os/macosx/macos.mm @@ -14,7 +14,6 @@ #include "../../string_func.h" #include "../../fileio_func.h" #include -#include #define Rect OTTDRect #define Point OTTDPoint diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index b1040d1d5f..b941e642ac 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -27,7 +27,6 @@ #include #include "../../language.h" #include "../../thread.h" -#include #include "../../safeguards.h" diff --git a/src/roadveh.h b/src/roadveh.h index 79ff9dbe0c..4881bb6b20 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -17,7 +17,6 @@ #include "road.h" #include "road_map.h" #include "newgrf_engine.h" -#include struct RoadVehicle; diff --git a/src/saveload/map_sl.cpp b/src/saveload/map_sl.cpp index 2809ad9cfd..fd0ccaea79 100644 --- a/src/saveload/map_sl.cpp +++ b/src/saveload/map_sl.cpp @@ -15,7 +15,6 @@ #include "../map_func.h" #include "../core/bitmath_func.hpp" #include "../fios.h" -#include #include "../safeguards.h" diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 303c05f6e0..55a03cd846 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -33,7 +33,6 @@ #include "../timer/timer_game_calendar.h" #include "saveload_internal.h" #include "oldloader.h" -#include #include "table/strings.h" #include "../table/engines.h" diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index dfde9e911f..ead719c94f 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -43,7 +43,6 @@ #include "../fios.h" #include "../error.h" #include -#include #ifdef __EMSCRIPTEN__ # include #endif diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 1026fa5482..a940bc1c6d 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -23,8 +23,6 @@ #include "../company_func.h" #include "../disaster_vehicle.h" -#include - #include "../safeguards.h" /** diff --git a/src/script/api/script_controller.hpp b/src/script/api/script_controller.hpp index 58419fafb3..1a26c006d4 100644 --- a/src/script/api/script_controller.hpp +++ b/src/script/api/script_controller.hpp @@ -11,7 +11,6 @@ #define SCRIPT_CONTROLLER_HPP #include "script_types.hpp" -#include /** * The Controller, the class each Script should extend. It creates the Script, diff --git a/src/script/api/script_error.hpp b/src/script/api/script_error.hpp index 601e99dd0f..0fe7d92d56 100644 --- a/src/script/api/script_error.hpp +++ b/src/script/api/script_error.hpp @@ -12,7 +12,6 @@ #include "script_object.hpp" #include "script_companymode.hpp" -#include /** * Helper to write precondition enforcers for the script API in an abbreviated manner. diff --git a/src/script/api/script_list.hpp b/src/script/api/script_list.hpp index 52bfd64487..a4793500e6 100644 --- a/src/script/api/script_list.hpp +++ b/src/script/api/script_list.hpp @@ -12,8 +12,6 @@ #define SCRIPT_LIST_HPP #include "script_object.hpp" -#include -#include class ScriptListSorter; diff --git a/src/script/api/script_log_types.hpp b/src/script/api/script_log_types.hpp index b10ea0cea3..d868f9d120 100644 --- a/src/script/api/script_log_types.hpp +++ b/src/script/api/script_log_types.hpp @@ -10,8 +10,6 @@ #ifndef SCRIPT_LOG_TYPES_HPP #define SCRIPT_LOG_TYPES_HPP -#include - namespace ScriptLogTypes { /** * Log levels; The value is also feed to Debug() lvl. diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 4b809e9602..baaef05e3e 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -10,8 +10,6 @@ #ifndef SCRIPT_CONFIG_HPP #define SCRIPT_CONFIG_HPP -#include -#include #include "../core/smallmap_type.hpp" #include "../company_type.h" #include "../textfile_gui.h" diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 3666db38bd..8273b67ed0 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -11,7 +11,6 @@ #define SCRIPT_INSTANCE_HPP #include -#include #include #include "script_suspend.hpp" #include "script_log_types.hpp" diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp index 707eade0cd..9b0ad6bf31 100644 --- a/src/script/script_scanner.hpp +++ b/src/script/script_scanner.hpp @@ -10,7 +10,6 @@ #ifndef SCRIPT_SCANNER_HPP #define SCRIPT_SCANNER_HPP -#include #include "../fileio_func.h" #include "../string_func.h" diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 7e656d0a08..3154ef096c 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -20,7 +20,6 @@ #include "../core/alloc_func.hpp" #include -#include /** * In the memory allocator for Squirrel we want to directly use malloc/realloc, so when the OS diff --git a/src/settings_table.h b/src/settings_table.h index d662b6a576..062beca07d 100644 --- a/src/settings_table.h +++ b/src/settings_table.h @@ -12,7 +12,6 @@ #ifndef SETTINGS_TABLE_H #define SETTINGS_TABLE_H -#include #include "settings_internal.h" extern SettingTable _company_settings; diff --git a/src/ship.h b/src/ship.h index ec8a47e63f..3a9ea806af 100644 --- a/src/ship.h +++ b/src/ship.h @@ -10,8 +10,6 @@ #ifndef SHIP_H #define SHIP_H -#include - #include "vehicle_base.h" #include "water_map.h" diff --git a/src/station_base.h b/src/station_base.h index bd7f00b9f9..45c85c04c2 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -18,8 +18,6 @@ #include "linkgraph/linkgraph_type.h" #include "newgrf_storage.h" #include "bitmap_type.h" -#include -#include static const byte INITIAL_STATION_RATING = 175; diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 46db6601e4..4a8cf9b958 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -37,8 +37,6 @@ #include "table/strings.h" -#include - #include "safeguards.h" /** diff --git a/src/station_type.h b/src/station_type.h index 7696c0f087..8056feb57e 100644 --- a/src/station_type.h +++ b/src/station_type.h @@ -12,7 +12,6 @@ #include "core/smallstack_type.hpp" #include "tilearea_type.h" -#include typedef uint16 StationID; typedef uint16 RoadStopID; diff --git a/src/stdafx.h b/src/stdafx.h index bb803d74cf..74bd6601f0 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -53,6 +53,7 @@ #endif #include +#include #include #include #include @@ -65,12 +66,16 @@ #include #include #include +#include #include #include #include +#include #include +#include #include #include +#include #include #include #include diff --git a/src/tar_type.h b/src/tar_type.h index 56f6224fcc..69f8f04c4a 100644 --- a/src/tar_type.h +++ b/src/tar_type.h @@ -10,9 +10,6 @@ #ifndef TAR_TYPE_H #define TAR_TYPE_H -#include -#include - #include "fileio_type.h" diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp index dbcd3ccbbc..d42227d3f1 100644 --- a/src/terraform_cmd.cpp +++ b/src/terraform_cmd.cpp @@ -22,9 +22,6 @@ #include "table/strings.h" -#include -#include - #include "safeguards.h" /** Set of tiles. */ diff --git a/src/tests/landscape_partial_pixel_z.cpp b/src/tests/landscape_partial_pixel_z.cpp index f5c22786f7..7dc25bb083 100644 --- a/src/tests/landscape_partial_pixel_z.cpp +++ b/src/tests/landscape_partial_pixel_z.cpp @@ -13,7 +13,6 @@ #include "../landscape.h" #include "../slope_func.h" -#include /** * Check whether the addition of two slope's GetPartialPixelZ values results in diff --git a/src/tests/string_func.cpp b/src/tests/string_func.cpp index a8ddd56711..17c153cde9 100644 --- a/src/tests/string_func.cpp +++ b/src/tests/string_func.cpp @@ -12,7 +12,6 @@ #include "../3rdparty/catch2/catch.hpp" #include "../string_func.h" -#include /**** String compare/equals *****/ diff --git a/src/timer/timer_manager.h b/src/timer/timer_manager.h index 8d1200abea..56af0bdee8 100644 --- a/src/timer/timer_manager.h +++ b/src/timer/timer_manager.h @@ -13,8 +13,6 @@ #include "stdafx.h" -#include - template class BaseTimer; diff --git a/src/town.h b/src/town.h index 0a9711a45d..c8be077d22 100644 --- a/src/town.h +++ b/src/town.h @@ -16,7 +16,6 @@ #include "subsidy_type.h" #include "newgrf_storage.h" #include "cargotype.h" -#include template struct BuildingCounts { diff --git a/src/townname_type.h b/src/townname_type.h index 45290bc046..6012af3fbd 100644 --- a/src/townname_type.h +++ b/src/townname_type.h @@ -16,7 +16,6 @@ #include "newgrf_townname.h" #include "town_type.h" #include "string_type.h" -#include typedef std::set TownNames; diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 7323508294..f7c4282e0d 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -24,8 +24,6 @@ #include "network/network.h" #include "saveload/saveload.h" #include "timer/timer_game_calendar.h" -#include -#include const uint TILE_AXIAL_DISTANCE = 192; // Logical length of the tile in any DiagDirection used in vehicle movement. const uint TILE_CORNER_DISTANCE = 128; // Logical length of the tile corner crossing in any non-diagonal direction used in vehicle movement. diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 54602e12aa..568377710f 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -44,7 +44,6 @@ #import /* for MAXPATHLEN */ #import /* gettimeofday */ -#include /* The 10.12 SDK added new names for some enum constants and * deprecated the old ones. As there's no functional change in any diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm index 445d412303..88361dbc7a 100644 --- a/src/video/cocoa/cocoa_wnd.mm +++ b/src/video/cocoa/cocoa_wnd.mm @@ -34,7 +34,6 @@ #include "../../window_gui.h" #include "../../spritecache.h" #include "../../toolbar_gui.h" -#include #include "table/sprites.h" diff --git a/src/video/opengl.cpp b/src/video/opengl.cpp index b0176f19ad..c5e82425c3 100644 --- a/src/video/opengl.cpp +++ b/src/video/opengl.cpp @@ -36,7 +36,6 @@ #include "../debug.h" #include "../blitter/factory.hpp" #include "../zoom_func.h" -#include #include #include "../table/opengl_shader.h" diff --git a/src/viewport.cpp b/src/viewport.cpp index e1b1508e66..185f8bf082 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -92,7 +92,6 @@ #include "viewport_cmd.h" #include -#include #include #include "table/strings.h" diff --git a/src/viewport_sprite_sorter_sse4.cpp b/src/viewport_sprite_sorter_sse4.cpp index 3272645e5b..899dc37568 100644 --- a/src/viewport_sprite_sorter_sse4.cpp +++ b/src/viewport_sprite_sorter_sse4.cpp @@ -14,7 +14,6 @@ #include "smmintrin.h" #include "viewport_sprite_sorter.h" #include -#include #include #include "safeguards.h" diff --git a/src/widgets/slider_func.h b/src/widgets/slider_func.h index 7de929512c..652a6c5c2d 100644 --- a/src/widgets/slider_func.h +++ b/src/widgets/slider_func.h @@ -13,8 +13,6 @@ #include "../window_type.h" #include "../gfx_func.h" -#include - void DrawSliderWidget(Rect r, int min_value, int max_value, int value, const std::map &labels); bool ClickSliderWidget(Rect r, Point pt, int min_value, int max_value, int &value); diff --git a/src/window_gui.h b/src/window_gui.h index 7784c2dc8a..b36813aedf 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -10,8 +10,6 @@ #ifndef WINDOW_GUI_H #define WINDOW_GUI_H -#include - #include "vehiclelist.h" #include "vehicle_type.h" #include "viewport_type.h" From 83f2ad500e3b1cbf42e94fb1bc745561f6061bd7 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 May 2023 09:27:20 +0100 Subject: [PATCH 52/58] Codechange: stdarg.h include not needed as cstdarg is included. --- src/console.cpp | 2 -- src/debug.cpp | 1 - src/game/game_text.cpp | 2 -- src/gamelog.cpp | 2 -- src/music/os2_m.cpp | 1 - src/newgrf.cpp | 2 -- src/newgrf_debug_gui.cpp | 1 - src/openttd.cpp | 1 - src/script/squirrel.cpp | 2 -- src/string.cpp | 2 -- src/string_func.h | 1 - src/textbuf.cpp | 1 - src/window.cpp | 1 - 13 files changed, 19 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index fd0082e4be..96de9ac8b8 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -16,8 +16,6 @@ #include "console_func.h" #include "settings_type.h" -#include - #include "safeguards.h" static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in one command diff --git a/src/debug.cpp b/src/debug.cpp index 85c187afe8..c82d75236e 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -8,7 +8,6 @@ /** @file debug.cpp Handling of printing debug messages. */ #include "stdafx.h" -#include #include "console_func.h" #include "debug.h" #include "string_func.h" diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 9db7e52ad6..25ca95cbdd 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -21,8 +21,6 @@ #include "table/strings.h" #include "table/strgen_tables.h" -#include - #include "../safeguards.h" void CDECL StrgenWarningI(const std::string &msg) diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 42c8290f71..43809e7758 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -18,8 +18,6 @@ #include "timer/timer_game_tick.h" #include "rev.h" -#include - #include "safeguards.h" extern const SaveLoadVersion SAVEGAME_VERSION; ///< current savegame version diff --git a/src/music/os2_m.cpp b/src/music/os2_m.cpp index 449caf3738..1c898138ad 100644 --- a/src/music/os2_m.cpp +++ b/src/music/os2_m.cpp @@ -18,7 +18,6 @@ #define INCL_OS2MM #define INCL_WIN -#include #include #include diff --git a/src/newgrf.cpp b/src/newgrf.cpp index a89c47f12b..8c240e5d10 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -9,8 +9,6 @@ #include "stdafx.h" -#include - #include "debug.h" #include "fileio_func.h" #include "engine_func.h" diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index f903771303..c70ce6895f 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -8,7 +8,6 @@ /** @file newgrf_debug_gui.cpp GUIs for debugging NewGRFs. */ #include "stdafx.h" -#include #include "core/backup_type.hpp" #include "window_gui.h" #include "window_func.h" diff --git a/src/openttd.cpp b/src/openttd.cpp index 62a55f223c..168d82bcb9 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -76,7 +76,6 @@ #include "linkgraph/linkgraphschedule.h" -#include #include #include "safeguards.h" diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 3154ef096c..a59b7cff64 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -19,8 +19,6 @@ #include <../squirrel/sqvm.h> #include "../core/alloc_func.hpp" -#include - /** * In the memory allocator for Squirrel we want to directly use malloc/realloc, so when the OS * does not have enough memory the game does not go into unrecoverable error mode and kill the diff --git a/src/string.cpp b/src/string.cpp index 89ee7bad9d..c129c6426f 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -17,8 +17,6 @@ #include "table/control_codes.h" -#include -#include /* required for tolower() */ #include #include diff --git a/src/string_func.h b/src/string_func.h index 06ca838cd1..08e1600b73 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -24,7 +24,6 @@ #ifndef STRING_FUNC_H #define STRING_FUNC_H -#include #include #include "core/bitmath_func.hpp" diff --git a/src/textbuf.cpp b/src/textbuf.cpp index e9e996a30e..807b004804 100644 --- a/src/textbuf.cpp +++ b/src/textbuf.cpp @@ -8,7 +8,6 @@ /** @file textbuf.cpp Textbuffer handling. */ #include "stdafx.h" -#include #include "textbuf_type.h" #include "string_func.h" diff --git a/src/window.cpp b/src/window.cpp index d399318824..2233a5f42d 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -8,7 +8,6 @@ /** @file window.cpp Windowing system, widgets and events */ #include "stdafx.h" -#include #include "company_func.h" #include "gfx_func.h" #include "console_func.h" From 418888ac237d4f4560516c571f5a197fc66656db Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 17 May 2023 18:40:23 +0000 Subject: [PATCH 53/58] Update: Translations from eints romanian: 11 changes by bnegrut turkish: 14 changes by densxd --- src/lang/romanian.txt | 11 +++++++++++ src/lang/turkish.txt | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index afca5ec2dd..2a6f7bd62a 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -195,6 +195,7 @@ STR_UNITS_VELOCITY_IMPERIAL :{DECIMAL} mph STR_UNITS_VELOCITY_METRIC :{DECIMAL} km/h STR_UNITS_VELOCITY_SI :{DECIMAL} m/s STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL}{NBSP}dale/zi +STR_UNITS_VELOCITY_KNOTS :{DECIMAL}{NBSP}Noduri STR_UNITS_POWER_IMPERIAL :{DECIMAL}cp STR_UNITS_POWER_METRIC :{DECIMAL}cp @@ -930,8 +931,14 @@ STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Copiază # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Opţiuni +STR_GAME_OPTIONS_TAB_GENERAL :General +STR_GAME_OPTIONS_TAB_GRAPHICS :Grafică +STR_GAME_OPTIONS_TAB_SOUND_TT :{BLACK}Alegeți setările de sunet și muzică +STR_GAME_OPTIONS_VOLUME :Volum +STR_GAME_OPTIONS_MUSIC_VOLUME :Muzică +STR_GAME_OPTIONS_VOLUME_75 :75% STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Unitate monetară STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Alege unitatea monetară @@ -986,6 +993,8 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Alege in # Autosave dropdown ###length 5 STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Dezactivată +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_30_MINUTES :La fiecare 30 de minute +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_120_MINUTES :La fiecare 120 de minute STR_GAME_OPTIONS_LANGUAGE :{BLACK}Limba STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Alege limba în care doreşti afişată interfaţa @@ -1949,6 +1958,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :Unități de joc (dale/zi) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_KNOTS :Noduri STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Unitate putere vehicule: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Afişează puterea vehiculelor în interfaţă folosind unităţile selectate @@ -5082,6 +5092,7 @@ STR_ERROR_NO_BUOY :{WHITE}Nu exist STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Nu pot programa vehiculul... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehiculele pot aştepta numai în staţii STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Acest vehicul nu are oprire în această staţie +STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... orarul este incomplet # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... prea multe semne diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index 84914cec33..d3573c4d98 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -1042,6 +1042,13 @@ STR_GAME_OPTIONS_GUI_SCALE_3X :3x STR_GAME_OPTIONS_GUI_SCALE_4X :4x STR_GAME_OPTIONS_GUI_SCALE_5X :5x +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_FRAME :{BLACK}Otomatik anket +STR_GAME_OPTIONS_PARTICIPATE_SURVEY :{BLACK}Otomatik ankete katılın +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_TOOLTIP :{BLACK}Etkinleştirildiğinde, OpenTTD bir oyundan çıkarken bir anket gönderir +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK :{BLACK}Anket ve gizlilik hakkında +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :{BLACK}Bu, otomatik anket hakkında daha fazla bilgi içeren bir tarayıcı açar +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :{BLACK}Anket sonucunu önizleyin +STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :{BLACK}Mevcut çalışan oyunun anket sonucunu göster STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafikler @@ -2404,6 +2411,12 @@ STR_NETWORK_ASK_RELAY_NO :{BLACK}Hayır STR_NETWORK_ASK_RELAY_YES_ONCE :{BLACK}Evet, bu seferliğine STR_NETWORK_ASK_RELAY_YES_ALWAYS :{BLACK}Evet, bir daha sorma +STR_NETWORK_ASK_SURVEY_CAPTION :Otomatik ankete katılıyor musunuz? +STR_NETWORK_ASK_SURVEY_TEXT :Otomatik ankete katılmak ister misiniz?{}OpenTTD, bir oyundan çıkarken bir anket gönderir.{}Bunu, "Oyun Seçenekleri" altında istediğiniz zaman değiştirebilirsiniz. +STR_NETWORK_ASK_SURVEY_PREVIEW :Anket sonucunu önizleyin +STR_NETWORK_ASK_SURVEY_LINK :Anket ve gizlilik hakkında +STR_NETWORK_ASK_SURVEY_NO :Hayır +STR_NETWORK_ASK_SURVEY_YES :Evet STR_NETWORK_SPECTATORS :İzleyiciler @@ -4661,6 +4674,7 @@ STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisans STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} adlı {STRING}'nin benioku dosyası STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} adlı {STRING}'nin değişiklik kaydı STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} adlı {STRING}'nin lisansı +STR_TEXTFILE_SURVEY_RESULT_CAPTION :{WHITE}Anket sonucunun önizlemesi # Vehicle loading indicators From f454ec8d63be9442e8cb03f0db072e66f2332fca Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 May 2023 14:54:14 +0100 Subject: [PATCH 54/58] Fix: Don't rely on static initialization to set up sprite font caches. The order of static initialization is undefined, so this can cause initalization before relevant caches are initializations. --- src/fontcache.cpp | 11 +++++++++-- src/fontcache.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/fontcache.cpp b/src/fontcache.cpp index bcb9364994..93c3f01b26 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -65,9 +65,14 @@ int GetCharacterHeight(FontSize size) } -/* static */ FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) }; - +/* static */ FontCache *FontCache::caches[FS_END]; +/* static */ void FontCache::InitializeFontCaches() +{ + for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) { + if (FontCache::caches[fs] == nullptr) new SpriteFontCache(fs); /* FontCache inserts itself into to the cache. */ + } +} /* Check if a glyph should be rendered with anti-aliasing. */ bool GetFontAAState(FontSize size, bool check_blitter) @@ -136,6 +141,8 @@ extern void LoadCoreTextFont(FontSize fs); */ void InitFontCache(bool monospace) { + FontCache::InitializeFontCaches(); + for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { if (monospace != (fs == FS_MONO)) continue; diff --git a/src/fontcache.h b/src/fontcache.h index efc1496304..3241723f76 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -33,6 +33,8 @@ public: FontCache(FontSize fs); virtual ~FontCache(); + static void InitializeFontCaches(); + static int GetDefaultFontHeight(FontSize fs); /** From 72018badff0496878dbcb3c71f0b73279bf918e5 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 16 May 2023 23:53:33 +0100 Subject: [PATCH 55/58] Codechange: Swap SocketList map key/value around. This map is used store socket and address together, and, other than checking that the address does not already have a socket, the data layout does not seem particularly important. However, as address is the key, technically it should not be modified, and address may self-modify itself during comparisons. --- src/network/core/address.cpp | 4 ++-- src/network/core/address.h | 2 +- src/network/core/tcp_listen.h | 6 +++--- src/network/core/udp.cpp | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 9a2d3dc487..366c140e65 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -259,7 +259,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * * of course totally unneeded ;) */ if (sockets != nullptr) { NetworkAddress address(runp->ai_addr, (int)runp->ai_addrlen); - if (sockets->Contains(address)) continue; + if (std::any_of(sockets->begin(), sockets->end(), [&address](const auto &p) { return p.second == address; })) continue; } sock = func(runp); if (sock == INVALID_SOCKET) continue; @@ -284,7 +284,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * } NetworkAddress addr(runp->ai_addr, (int)runp->ai_addrlen); - (*sockets)[addr] = sock; + (*sockets)[sock] = addr; sock = INVALID_SOCKET; } freeaddrinfo (ai); diff --git a/src/network/core/address.h b/src/network/core/address.h index 7cf159fb5e..c82b42f556 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -19,7 +19,7 @@ class NetworkAddress; typedef std::vector NetworkAddressList; ///< Type for a list of addresses. -typedef SmallMap SocketList; ///< Type for a mapping between address and socket. +typedef SmallMap SocketList; ///< Type for a mapping between address and socket. /** * Wrapper for (un)resolved network addresses; there's no reason to transform diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 0c7b11df1f..4df240ae6a 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -114,7 +114,7 @@ public: /* take care of listener port */ for (auto &s : sockets) { - FD_SET(s.second, &read_fd); + FD_SET(s.first, &read_fd); } tv.tv_sec = tv.tv_usec = 0; // don't block at all. @@ -122,7 +122,7 @@ public: /* accept clients.. */ for (auto &s : sockets) { - if (FD_ISSET(s.second, &read_fd)) AcceptClient(s.second); + if (FD_ISSET(s.first, &read_fd)) AcceptClient(s.first); } /* read stuff from clients */ @@ -164,7 +164,7 @@ public: static void CloseListeners() { for (auto &s : sockets) { - closesocket(s.second); + closesocket(s.first); } sockets.clear(); Debug(net, 5, "[{}] Closed listeners", Tsocket::GetName()); diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index f1f74bcf34..9f4a09e67c 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -59,7 +59,7 @@ bool NetworkUDPSocketHandler::Listen() void NetworkUDPSocketHandler::CloseSocket() { for (auto &s : this->sockets) { - closesocket(s.second); + closesocket(s.first); } this->sockets.clear(); } @@ -81,20 +81,20 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a NetworkAddress send(*recv); /* Not the same type */ - if (!send.IsFamily(s.first.GetAddress()->ss_family)) continue; + if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue; p->PrepareToSend(); if (broadcast) { /* Enable broadcast */ unsigned long val = 1; - if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { + if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { Debug(net, 1, "Setting broadcast mode failed: {}", NetworkError::GetLast().AsString()); } } /* Send the buffer */ - ssize_t res = p->TransferOut(sendto, s.second, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); + ssize_t res = p->TransferOut(sendto, s.first, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); Debug(net, 7, "sendto({})", send.GetAddressAsString()); /* Check for any errors, but ignore it otherwise */ @@ -119,8 +119,8 @@ void NetworkUDPSocketHandler::ReceivePackets() socklen_t client_len = sizeof(client_addr); /* Try to receive anything */ - SetNonBlocking(s.second); // Some OSes seem to lose the non-blocking status of the socket - ssize_t nbytes = p.TransferIn(recvfrom, s.second, 0, (struct sockaddr *)&client_addr, &client_len); + SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket + ssize_t nbytes = p.TransferIn(recvfrom, s.first, 0, (struct sockaddr *)&client_addr, &client_len); /* Did we get the bytes for the base header of the packet? */ if (nbytes <= 0) break; // No data, i.e. no packet From c38df2d5895cbb6a3834753ba4650221a602d915 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 16 May 2023 20:50:41 +0100 Subject: [PATCH 56/58] Codechange: Use std::map instead of custom SmallMap. --- src/base_media_base.h | 1 - src/core/CMakeLists.txt | 1 - src/core/smallmap_type.hpp | 147 ---------------------------- src/fios.h | 2 +- src/fontcache/truetypefontcache.cpp | 6 +- src/fontcache/truetypefontcache.h | 3 +- src/gamelog.cpp | 32 +++--- src/gamelog_internal.h | 4 +- src/gfx_layout.cpp | 17 ++-- src/gfx_layout.h | 6 +- src/gfx_layout_fallback.cpp | 14 +-- src/linkgraph/linkgraph.h | 1 - src/network/core/address.h | 3 +- src/newgrf.cpp | 6 +- src/newgrf_config.cpp | 2 +- src/newgrf_config.h | 3 +- src/newgrf_debug_gui.cpp | 10 +- src/newgrf_gui.cpp | 7 +- src/newgrf_text.cpp | 1 - src/os/macosx/font_osx.cpp | 1 + src/os/macosx/string_osx.cpp | 3 +- src/os/windows/font_win32.cpp | 1 + src/osk_gui.cpp | 4 +- src/saveload/company_sl.cpp | 6 +- src/script/script_config.hpp | 1 - src/town_cmd.cpp | 6 +- src/vehicle.cpp | 11 +-- src/vehicle_base.h | 3 +- src/window.cpp | 11 +-- src/window_gui.h | 3 +- 30 files changed, 81 insertions(+), 235 deletions(-) delete mode 100644 src/core/smallmap_type.hpp diff --git a/src/base_media_base.h b/src/base_media_base.h index d78539f730..1a2c64422e 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -11,7 +11,6 @@ #define BASE_MEDIA_BASE_H #include "fileio_func.h" -#include "core/smallmap_type.hpp" #include "gfx_type.h" #include "textfile_type.h" #include "textfile_gui.h" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 86e5124ef6..b0576299a2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -22,7 +22,6 @@ add_files( pool_type.hpp random_func.cpp random_func.hpp - smallmap_type.hpp smallstack_type.hpp smallvec_type.hpp span_type.hpp diff --git a/src/core/smallmap_type.hpp b/src/core/smallmap_type.hpp deleted file mode 100644 index de3a72be70..0000000000 --- a/src/core/smallmap_type.hpp +++ /dev/null @@ -1,147 +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 . - */ - -/** @file smallmap_type.hpp Simple mapping class targeted for small sets of data. Stored data shall be POD ("Plain Old Data")! */ - -#ifndef SMALLMAP_TYPE_HPP -#define SMALLMAP_TYPE_HPP - -#include "smallvec_type.hpp" -#include - -/** - * Implementation of simple mapping class. - * It has inherited accessors from std::vector(). - * @tparam T Key type. - * @tparam U Value type. - * @tparam S Unit of allocation. - * - * @see std::vector - */ -template -struct SmallMap : std::vector > { - typedef std::pair Pair; - typedef Pair *iterator; - typedef const Pair *const_iterator; - - /** Creates new SmallMap. Data are initialized in std::vector constructor */ - inline SmallMap() { } - /** Data are freed in std::vector destructor */ - inline ~SmallMap() { } - - /** - * Finds given key in this map - * @param key key to find - * @return &Pair(key, data) if found, this->End() if not - */ - inline typename std::vector::const_iterator Find(const T &key) const - { - return std::find_if(std::vector::begin(), std::vector::end(), [&key](const Pair &pair) { return key == pair.first; }); - } - - /** - * Finds given key in this map - * @param key key to find - * @return &Pair(key, data) if found, this->End() if not - */ - inline Pair *Find(const T &key) - { - for (uint i = 0; i < std::vector::size(); i++) { - if (key == std::vector::operator[](i).first) return &std::vector::operator[](i); - } - return this->End(); - } - - inline const Pair *End() const - { - return std::vector::data() + std::vector::size(); - } - - inline Pair *End() - { - return std::vector::data() + std::vector::size(); - } - - - /** - * Tests whether a key is assigned in this map. - * @param key key to test - * @return true iff the item is present - */ - inline bool Contains(const T &key) const - { - return this->Find(key) != std::vector::end(); - } - - /** - * Tests whether a key is assigned in this map. - * @param key key to test - * @return true iff the item is present - */ - inline bool Contains(const T &key) - { - return this->Find(key) != this->End(); - } - - /** - * Removes given pair from this map - * @param pair pair to remove - * @note it has to be pointer to pair in this map. It is overwritten by the last item. - */ - inline void Erase(Pair *pair) - { - assert(pair >= std::vector::data() && pair < this->End()); - auto distance = pair - std::vector::data(); - std::vector::erase(std::vector::begin() + distance); - } - - /** - * Removes given key from this map - * @param key key to remove - * @return true iff the key was found - * @note last item is moved to its place, so don't increase your iterator if true is returned! - */ - inline bool Erase(const T &key) - { - auto *pair = this->Find(key); - if (pair == this->End()) return false; - - this->Erase(pair); - return true; - } - - /** - * Adds new item to this map. - * @param key key - * @param data data - * @return true iff the key wasn't already present - */ - inline bool Insert(const T &key, const U &data) - { - if (this->Contains(key)) return false; - std::vector::emplace_back(key, data); - return true; - } - - /** - * Returns data belonging to this key - * @param key key - * @return data belonging to this key - * @note if this key wasn't present, new entry is created - */ - inline U &operator[](const T &key) - { - for (uint i = 0; i < std::vector::size(); i++) { - if (key == std::vector::operator[](i).first) return std::vector::operator[](i).second; - } - Pair &n = std::vector::emplace_back(); - n.first = key; - return n.second; - } -}; - -#endif /* SMALLMAP_TYPE_HPP */ diff --git a/src/fios.h b/src/fios.h index bb850e05a9..58c7844a32 100644 --- a/src/fios.h +++ b/src/fios.h @@ -25,7 +25,7 @@ enum SaveLoadInvalidateWindowData { SLIWD_FILTER_CHANGES, ///< The filename filter has changed (via the editbox) }; -typedef SmallMap CompanyPropertiesMap; +using CompanyPropertiesMap = std::map; /** * Container for loading in mode SL_LOAD_CHECK. diff --git a/src/fontcache/truetypefontcache.cpp b/src/fontcache/truetypefontcache.cpp index 22517f017a..6933b9ae78 100644 --- a/src/fontcache/truetypefontcache.cpp +++ b/src/fontcache/truetypefontcache.cpp @@ -167,14 +167,14 @@ const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key) const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length) { - const FontTable::iterator iter = this->font_tables.Find(tag); - if (iter != this->font_tables.data() + this->font_tables.size()) { + const auto iter = this->font_tables.find(tag); + if (iter != this->font_tables.end()) { length = iter->second.first; return iter->second.second; } const void *result = this->InternalGetFontTable(tag, length); - this->font_tables.Insert(tag, std::pair(length, result)); + this->font_tables[tag] = std::pair(length, result); return result; } diff --git a/src/fontcache/truetypefontcache.h b/src/fontcache/truetypefontcache.h index f8ef423909..18f248f2cb 100644 --- a/src/fontcache/truetypefontcache.h +++ b/src/fontcache/truetypefontcache.h @@ -10,7 +10,6 @@ #ifndef TRUETYPEFONTCACHE_H #define TRUETYPEFONTCACHE_H -#include "../core/smallmap_type.hpp" #include "../fontcache.h" @@ -28,7 +27,7 @@ protected: int req_size; ///< Requested font size. int used_size; ///< Used font size. - typedef SmallMap > FontTable; ///< Table with font table cache + using FontTable = std::map>; ///< Table with font table cache FontTable font_tables; ///< Cached font tables. /** Container for information about a glyph. */ diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 43809e7758..cba76e0a61 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -233,25 +233,25 @@ void Gamelog::Print(std::function proc) const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum); fmt::format_to(output_iterator, "Added NewGRF: "); AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc); - GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); - if (gm != grf_names.End() && !gm->second.was_missing) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was already added!"); + auto gm = grf_names.find(this->grfid); + if (gm != grf_names.end() && !gm->second.was_missing) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was already added!"); grf_names[this->grfid] = gc; } /* virtual */ void LoggedChangeGRFRemoved::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) { /* A NewGRF got removed from the game, either manually or by it missing when loading the game. */ - GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + auto gm = grf_names.find(this->grfid); fmt::format_to(output_iterator, action_type == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "); - AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) { + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr); + if (gm == grf_names.end()) { fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); } else { if (action_type == GLAT_LOAD) { /* Missing grfs on load are not removed from the configuration */ gm->second.was_missing = true; } else { - grf_names.Erase(gm); + grf_names.erase(gm); } } } @@ -262,38 +262,38 @@ void Gamelog::Print(std::function proc) const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum); fmt::format_to(output_iterator, "Compatible NewGRF loaded: "); AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc); - if (!grf_names.Contains(this->grfid)) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + if (grf_names.count(this->grfid) == 0) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); grf_names[this->grfid] = gc; } /* virtual */ void LoggedChangeGRFParameterChanged::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) { /* A parameter of a NewGRF got changed after the game was started. */ - GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + auto gm = grf_names.find(this->grfid); fmt::format_to(output_iterator, "GRF parameter changed: "); - AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr); + if (gm == grf_names.end()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); } /* virtual */ void LoggedChangeGRFMoved::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) { /* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */ - GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + auto gm = grf_names.find(this->grfid); fmt::format_to(output_iterator, "GRF order changed: {:08X} moved {} places {}", BSWAP32(this->grfid), abs(this->offset), this->offset >= 0 ? "down" : "up" ); - AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr); + if (gm == grf_names.end()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); } /* virtual */ void LoggedChangeGRFBug::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) { /* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */ - GrfIDMapping::Pair *gm = grf_names.Find(this->grfid); + auto gm = grf_names.find(this->grfid); assert(this->bug == GBUG_VEH_LENGTH); fmt::format_to(output_iterator, "Rail vehicle changes length outside a depot: GRF ID {:08X}, internal ID 0x{:X}", BSWAP32(this->grfid), this->data); - AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); - if (gm == grf_names.End()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); + AddGrfInfo(output_iterator, this->grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr); + if (gm == grf_names.end()) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!"); } /* virtual */ void LoggedChangeEmergencySave::FormatTo(std::back_insert_iterator &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type) diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h index bd8957a54c..463c0eab0e 100644 --- a/src/gamelog_internal.h +++ b/src/gamelog_internal.h @@ -19,14 +19,14 @@ * So if the gamelog tells a Grf is missing we do not know whether it was readded or completely removed * at some later point. */ -struct GRFPresence{ +struct GRFPresence { const GRFConfig *gc; ///< GRFConfig, if known bool was_missing; ///< Grf was missing during some gameload in the past GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {} GRFPresence() = default; }; -typedef SmallMap GrfIDMapping; +using GrfIDMapping = std::map; struct LoggedChange { LoggedChange(GamelogChangeType type = GLCT_NONE) : ct(type) {} diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 2c4e0d3ed4..3755851cdb 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -103,8 +103,8 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s continue; } - if (!fontMapping.Contains(buff - buff_begin)) { - fontMapping.Insert(buff - buff_begin, f); + if (fontMapping.count(buff - buff_begin) == 0) { + fontMapping[buff - buff_begin] = f; } f = Layouter::GetFont(state.fontsize, state.cur_colour); } @@ -112,8 +112,8 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s /* Better safe than sorry. */ *buff = '\0'; - if (!fontMapping.Contains(buff - buff_begin)) { - fontMapping.Insert(buff - buff_begin, f); + if (fontMapping.count(buff - buff_begin) == 0) { + fontMapping[buff - buff_begin] = f; } line.layout = T::GetParagraphLayout(buff_begin, buff, fontMapping); line.state_after = state; @@ -296,12 +296,11 @@ ptrdiff_t Layouter::GetCharAtPosition(int x) const */ Font *Layouter::GetFont(FontSize size, TextColour colour) { - FontColourMap::iterator it = fonts[size].Find(colour); - if (it != fonts[size].End()) return it->second; + FontColourMap::iterator it = fonts[size].find(colour); + if (it != fonts[size].end()) return it->second; - Font *f = new Font(size, colour); - fonts[size].emplace_back(colour, f); - return f; + fonts[size][colour] = new Font(size, colour); + return fonts[size][colour]; } /** diff --git a/src/gfx_layout.h b/src/gfx_layout.h index f66bebefa0..d2fd987af2 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -12,7 +12,7 @@ #include "fontcache.h" #include "gfx_func.h" -#include "core/smallmap_type.hpp" +#include "core/math_func.hpp" #include #include @@ -81,7 +81,7 @@ public: }; /** Mapping from index to font. */ -typedef SmallMap FontMap; +using FontMap = std::map; /** * Interface to glue fallback and normal layouter into one. @@ -169,7 +169,7 @@ private: static LineCacheItem &GetCachedParagraphLayout(std::string_view str, const FontState &state); - typedef SmallMap FontColourMap; + using FontColourMap = std::map; static FontColourMap fonts[FS_END]; public: static Font *GetFont(FontSize size, TextColour colour); diff --git a/src/gfx_layout_fallback.cpp b/src/gfx_layout_fallback.cpp index dbb2f0cc28..f16c8551ef 100644 --- a/src/gfx_layout_fallback.cpp +++ b/src/gfx_layout_fallback.cpp @@ -266,7 +266,7 @@ const ParagraphLayouter::VisualRun &FallbackParagraphLayout::FallbackLine::GetVi */ FallbackParagraphLayout::FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs) { - assert(runs.End()[-1].first == length); + assert(runs.rbegin()->first == length); } /** @@ -295,15 +295,15 @@ std::unique_ptr FallbackParagraphLayout::NextLine if (*this->buffer == '\0') { /* Only a newline. */ this->buffer = nullptr; - l->emplace_back(this->runs.front().second, this->buffer, 0, 0); + l->emplace_back(this->runs.begin()->second, this->buffer, 0, 0); return l; } int offset = this->buffer - this->buffer_begin; - FontMap::iterator iter = this->runs.data(); + FontMap::iterator iter = this->runs.begin(); while (iter->first <= offset) { - iter++; - assert(iter != this->runs.End()); + ++iter; + assert(iter != this->runs.end()); } const FontCache *fc = iter->second->fc; @@ -325,8 +325,8 @@ std::unique_ptr FallbackParagraphLayout::NextLine if (this->buffer == next_run) { int w = l->GetWidth(); l->emplace_back(iter->second, begin, this->buffer - begin, w); - iter++; - assert(iter != this->runs.End()); + ++iter; + assert(iter != this->runs.end()); next_run = this->buffer_begin + iter->first; begin = this->buffer; diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 82d5210396..521684c8a1 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -11,7 +11,6 @@ #define LINKGRAPH_H #include "../core/pool_type.hpp" -#include "../core/smallmap_type.hpp" #include "../station_base.h" #include "../cargotype.h" #include "../date_type.h" diff --git a/src/network/core/address.h b/src/network/core/address.h index c82b42f556..3c9088013c 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -14,12 +14,11 @@ #include "config.h" #include "../../company_type.h" #include "../../string_func.h" -#include "../../core/smallmap_type.hpp" class NetworkAddress; typedef std::vector NetworkAddressList; ///< Type for a list of addresses. -typedef SmallMap SocketList; ///< Type for a mapping between address and socket. +using SocketList = std::map; ///< Type for a mapping between address and socket. /** * Wrapper for (un)resolved network addresses; there's no reason to transform diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 8c240e5d10..b93caedb31 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -8372,13 +8372,13 @@ static bool ChangeGRFParamValueNames(ByteReader *buf) byte langid = buf->ReadByte(); const char *name_string = buf->ReadString(); - std::pair *val_name = _cur_parameter->value_names.Find(id); - if (val_name != _cur_parameter->value_names.End()) { + auto val_name = _cur_parameter->value_names.find(id); + if (val_name != _cur_parameter->value_names.end()) { AddGRFTextToList(val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); } else { GRFTextList list; AddGRFTextToList(list, langid, _cur.grfconfig->ident.grfid, false, name_string); - _cur_parameter->value_names.Insert(id, list); + _cur_parameter->value_names[id] = list; } type = buf->ReadByte(); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index b2b29a5b89..ed134c1741 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -264,7 +264,7 @@ void GRFParameterInfo::Finalize() { this->complete_labels = true; for (uint32 value = this->min_value; value <= this->max_value; value++) { - if (!this->value_names.Contains(value)) { + if (this->value_names.count(value) == 0) { this->complete_labels = false; break; } diff --git a/src/newgrf_config.h b/src/newgrf_config.h index d5d085b702..3d345e6d95 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -12,7 +12,6 @@ #include "strings_type.h" #include "core/alloc_type.hpp" -#include "core/smallmap_type.hpp" #include "misc/countedptr.hpp" #include "fileio_type.h" #include "textfile_type.h" @@ -143,7 +142,7 @@ struct GRFParameterInfo { byte param_nr; ///< GRF parameter to store content in byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter - SmallMap value_names; ///< Names for each value. + std::map value_names; ///< Names for each value. bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index c70ce6895f..8dd2dab408 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -818,7 +818,7 @@ struct SpriteAlignerWindow : Window { SpriteID current_sprite; ///< The currently shown sprite. Scrollbar *vscroll; - SmallMap offs_start_map; ///< Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window. + std::map offs_start_map; ///< Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window. static bool centre; static bool crosshair; @@ -854,7 +854,7 @@ struct SpriteAlignerWindow : Window { /* Relative offset is new absolute offset - starting absolute offset. * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet). */ - const auto key_offs_pair = this->offs_start_map.Find(this->current_sprite); + const auto key_offs_pair = this->offs_start_map.find(this->current_sprite); if (key_offs_pair != this->offs_start_map.end()) { SetDParam(0, spr->x_offs - key_offs_pair->second.first); SetDParam(1, spr->y_offs - key_offs_pair->second.second); @@ -992,8 +992,8 @@ struct SpriteAlignerWindow : Window { Sprite *spr = const_cast(GetSprite(this->current_sprite, SpriteType::Normal)); /* Remember the original offsets of the current sprite, if not already in mapping. */ - if (!(this->offs_start_map.Contains(this->current_sprite))) { - this->offs_start_map.Insert(this->current_sprite, XyOffs(spr->x_offs, spr->y_offs)); + if (this->offs_start_map.count(this->current_sprite) == 0) { + this->offs_start_map[this->current_sprite] = XyOffs(spr->x_offs, spr->y_offs); } switch (widget) { /* Move eight units at a time if ctrl is pressed. */ @@ -1010,7 +1010,7 @@ struct SpriteAlignerWindow : Window { case WID_SA_RESET_REL: /* Reset the starting offsets for the current sprite. */ - this->offs_start_map.Erase(this->current_sprite); + this->offs_start_map.erase(this->current_sprite); this->SetDirty(); break; diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 9e8449834f..b11c390970 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -283,8 +283,9 @@ struct NewGRFParametersWindow : public Window { } SetDParam(2, STR_JUST_INT); SetDParam(3, current_value); - if (par_info->value_names.Contains(current_value)) { - const char *label = GetGRFStringFromGRFText(par_info->value_names.Find(current_value)->second); + auto it = par_info->value_names.find(current_value); + if (it != par_info->value_names.end()) { + const char *label = GetGRFStringFromGRFText(it->second); if (label != nullptr) { SetDParam(2, STR_JUST_RAW_STRING); SetDParamStr(3, label); @@ -380,7 +381,7 @@ struct NewGRFParametersWindow : public Window { DropDownList list; for (uint32 i = par_info->min_value; i <= par_info->max_value; i++) { - list.emplace_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.Find(i)->second), i, false)); + list.emplace_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.find(i)->second), i, false)); } ShowDropDownListAt(this, std::move(list), old_val, -1, wi_rect, COLOUR_ORANGE); diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 0e30cde965..92d2de438c 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -26,7 +26,6 @@ #include "date_type.h" #include "debug.h" #include "core/alloc_type.hpp" -#include "core/smallmap_type.hpp" #include "language.h" #include diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index 521e766024..bdbbcada64 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -10,6 +10,7 @@ #include "../../stdafx.h" #include "../../debug.h" #include "font_osx.h" +#include "../../core/math_func.hpp" #include "../../blitter/factory.hpp" #include "../../error_func.h" #include "../../fileio_func.h" diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index f089c630c5..e6c37249ec 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -102,8 +102,7 @@ public: /* Extract font information for this run. */ CFRange chars = CTRunGetStringRange(run); - auto map = fontMapping.begin(); - while (map < fontMapping.end() - 1 && map->first <= chars.location) map++; + auto map = fontMapping.upper_bound(chars.location); this->emplace_back(run, map->second, buff); } diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 7de608c97c..def4f57552 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -12,6 +12,7 @@ #include "../../blitter/factory.hpp" #include "../../core/alloc_func.hpp" #include "../../core/math_func.hpp" +#include "../../core/mem_func.hpp" #include "../../error_func.h" #include "../../fileio_func.h" #include "../../fontdetection.h" diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index b6f946c791..307cc4f793 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -50,8 +50,8 @@ struct OskWindow : public Window { NWidgetCore *par_wid = parent->GetWidget(button); assert(par_wid != nullptr); - assert(parent->querystrings.Contains(button)); - this->qs = parent->querystrings.Find(button)->second; + assert(parent->querystrings.count(button) != 0); + this->qs = parent->querystrings.find(button)->second; this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : this->qs->caption; this->text_btn = button; this->text = &this->qs->text; diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index b15e34ac1b..8457820d2e 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -548,7 +548,11 @@ struct PLYRChunkHandler : ChunkHandler { cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; } - if (!_load_check_data.companies.Insert(index, cprops)) delete cprops; + if (_load_check_data.companies.count(index) == 0) { + _load_check_data.companies[index] = cprops; + } else { + delete cprops; + } } } diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index baaef05e3e..684555e411 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -10,7 +10,6 @@ #ifndef SCRIPT_CONFIG_HPP #define SCRIPT_CONFIG_HPP -#include "../core/smallmap_type.hpp" #include "../company_type.h" #include "../textfile_gui.h" #include "script_instance.hpp" diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index aee1b329bb..ad110ae006 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -3645,7 +3645,7 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold) } static bool _town_rating_test = false; ///< If \c true, town rating is in test-mode. -static SmallMap _town_test_ratings; ///< Map of towns to modified ratings, while in town rating test-mode. +static std::map _town_test_ratings; ///< Map of towns to modified ratings, while in town rating test-mode. /** * Switch the town rating to test-mode, to allow commands to be tested without affecting current ratings. @@ -3675,8 +3675,8 @@ void SetTownRatingTestMode(bool mode) static int GetRating(const Town *t) { if (_town_rating_test) { - SmallMap::iterator it = _town_test_ratings.Find(t); - if (it != _town_test_ratings.End()) { + auto it = _town_test_ratings.find(t); + if (it != _town_test_ratings.end()) { return it->second; } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index cb34349214..b61764e261 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -678,13 +678,12 @@ void ResetVehicleColourMap() * List of vehicles that should check for autoreplace this tick. * Mapping of vehicle -> leave depot immediately after autoreplace. */ -typedef SmallMap AutoreplaceMap; +using AutoreplaceMap = std::map; static AutoreplaceMap _vehicles_to_autoreplace; void InitializeVehicles() { _vehicles_to_autoreplace.clear(); - _vehicles_to_autoreplace.shrink_to_fit(); ResetVehicleHash(); } @@ -2357,13 +2356,13 @@ void Vehicle::HandleLoading(bool mode) * Get a map of cargoes and free capacities in the consist. * @param capacities Map to be filled with cargoes and capacities. */ -void Vehicle::GetConsistFreeCapacities(SmallMap &capacities) const +void Vehicle::GetConsistFreeCapacities(std::map &capacities) const { for (const Vehicle *v = this; v != nullptr; v = v->Next()) { if (v->cargo_cap == 0) continue; - std::pair *pair = capacities.Find(v->cargo_type); - if (pair == capacities.End()) { - capacities.push_back({v->cargo_type, v->cargo_cap - v->cargo.StoredCount()}); + auto pair = capacities.find(v->cargo_type); + if (pair == capacities.end()) { + capacities[v->cargo_type] = v->cargo_cap - v->cargo.StoredCount(); } else { pair->second += v->cargo_cap - v->cargo.StoredCount(); } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index f7c4282e0d..8aa5fc0873 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -10,7 +10,6 @@ #ifndef VEHICLE_BASE_H #define VEHICLE_BASE_H -#include "core/smallmap_type.hpp" #include "track_type.h" #include "command_type.h" #include "order_base.h" @@ -391,7 +390,7 @@ public: void HandleLoading(bool mode = false); - void GetConsistFreeCapacities(SmallMap &capacities) const; + void GetConsistFreeCapacities(std::map &capacities) const; uint GetConsistTotalCapacity() const; diff --git a/src/window.cpp b/src/window.cpp index 2233a5f42d..5c056146be 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -340,7 +340,7 @@ Scrollbar *Window::GetScrollbar(uint widnum) */ const QueryString *Window::GetQueryString(uint widnum) const { - auto query = this->querystrings.Find(widnum); + auto query = this->querystrings.find(widnum); return query != this->querystrings.end() ? query->second : nullptr; } @@ -351,8 +351,8 @@ const QueryString *Window::GetQueryString(uint widnum) const */ QueryString *Window::GetQueryString(uint widnum) { - SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : nullptr; + auto query = this->querystrings.find(widnum); + return query != this->querystrings.end() ? query->second : nullptr; } /** @@ -360,8 +360,7 @@ QueryString *Window::GetQueryString(uint widnum) */ void Window::UpdateQueryStringSize() { - for (auto &qs : this->querystrings) - { + for (auto &qs : this->querystrings) { qs.second->text.UpdateSize(); } } @@ -1912,7 +1911,7 @@ static void DecreaseWindowCounters() } /* Handle editboxes */ - for (SmallMap::Pair &pair : w->querystrings) { + for (auto &pair : w->querystrings) { pair.second->HandleEditBox(w, pair.first); } diff --git a/src/window_gui.h b/src/window_gui.h index b36813aedf..953282bf7b 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -17,7 +17,6 @@ #include "tile_type.h" #include "widget_type.h" #include "core/smallvec_type.hpp" -#include "core/smallmap_type.hpp" #include "string_type.h" /** @@ -250,7 +249,7 @@ public: ViewportData *viewport; ///< Pointer to viewport data, if present. const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus. - SmallMap querystrings; ///< QueryString associated to WWT_EDITBOX widgets. + std::map querystrings; ///< QueryString associated to WWT_EDITBOX widgets. NWidgetBase *nested_root; ///< Root of the nested tree. NWidgetBase **nested_array; ///< Array of pointers into the tree. Do not access directly, use #Window::GetWidget() instead. uint nested_array_size; ///< Size of the nested array. From bf8f24f9a83fb5f05092e0ee2ba6c72e3cf3e156 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 May 2023 08:36:54 +0100 Subject: [PATCH 57/58] Codechange: Use unique_ptr for text layout font mapping. This must stay a pointer as the value passed to other structures. --- src/gfx_layout.cpp | 9 +++------ src/gfx_layout.h | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 3755851cdb..73420b0add 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -297,10 +297,10 @@ ptrdiff_t Layouter::GetCharAtPosition(int x) const Font *Layouter::GetFont(FontSize size, TextColour colour) { FontColourMap::iterator it = fonts[size].find(colour); - if (it != fonts[size].end()) return it->second; + if (it != fonts[size].end()) return it->second.get(); - fonts[size][colour] = new Font(size, colour); - return fonts[size][colour]; + fonts[size][colour] = std::make_unique(size, colour); + return fonts[size][colour].get(); } /** @@ -309,9 +309,6 @@ Font *Layouter::GetFont(FontSize size, TextColour colour) */ void Layouter::ResetFontCache(FontSize size) { - for (auto &pair : fonts[size]) { - delete pair.second; - } fonts[size].clear(); /* We must reset the linecache since it references the just freed fonts */ diff --git a/src/gfx_layout.h b/src/gfx_layout.h index d2fd987af2..181bef5561 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -80,7 +80,7 @@ public: Font(FontSize size, TextColour colour); }; -/** Mapping from index to font. */ +/** Mapping from index to font. The pointer is owned by FontColourMap. */ using FontMap = std::map; /** @@ -169,7 +169,7 @@ private: static LineCacheItem &GetCachedParagraphLayout(std::string_view str, const FontState &state); - using FontColourMap = std::map; + using FontColourMap = std::map>; static FontColourMap fonts[FS_END]; public: static Font *GetFont(FontSize size, TextColour colour); From 91e140c722d944a70bae3d5a2450f4e23cd900d8 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 18 May 2023 08:38:35 +0100 Subject: [PATCH 58/58] Codechange: Use unique_ptr for fios company properties. This is the data used to show company names in the saveload window. --- src/fios.h | 2 +- src/fios_gui.cpp | 3 --- src/saveload/company_sl.cpp | 8 +++----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/fios.h b/src/fios.h index 58c7844a32..70986135a2 100644 --- a/src/fios.h +++ b/src/fios.h @@ -25,7 +25,7 @@ enum SaveLoadInvalidateWindowData { SLIWD_FILTER_CHANGES, ///< The filename filter has changed (via the editbox) }; -using CompanyPropertiesMap = std::map; +using CompanyPropertiesMap = std::map>; /** * Container for loading in mode SL_LOAD_CHECK. diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 07e55384d7..7d0e8fe556 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -55,9 +55,6 @@ void LoadCheckData::Clear() this->current_date = 0; this->settings = {}; - for (auto &pair : this->companies) { - delete pair.second; - } companies.clear(); this->gamelog.Reset(); diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 8457820d2e..0a474ae839 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -527,8 +527,8 @@ struct PLYRChunkHandler : ChunkHandler { int index; while ((index = SlIterateArray()) != -1) { - CompanyProperties *cprops = new CompanyProperties(); - SlObject(cprops, slt); + std::unique_ptr cprops = std::make_unique(); + SlObject(cprops.get(), slt); /* We do not load old custom names */ if (IsSavegameVersionBefore(SLV_84)) { @@ -549,9 +549,7 @@ struct PLYRChunkHandler : ChunkHandler { } if (_load_check_data.companies.count(index) == 0) { - _load_check_data.companies[index] = cprops; - } else { - delete cprops; + _load_check_data.companies[index] = std::move(cprops); } } }