diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 421d8ca956..78ac7cd2b6 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -108,6 +108,8 @@ 939A359F20C12FDE00630B3F /* Paint.Surface.h in Headers */ = {isa = PBXBuildFile; fileRef = 939A359D20C12FDD00630B3F /* Paint.Surface.h */; }; 939A35A020C12FDE00630B3F /* Paint.TileElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 939A359E20C12FDE00630B3F /* Paint.TileElement.h */; }; 939A35A220C12FFD00630B3F /* InteractiveConsole.h in Headers */ = {isa = PBXBuildFile; fileRef = 939A35A120C12FFD00630B3F /* InteractiveConsole.h */; }; + 93AE2389252F948A00CD03C3 /* Formatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 93AE2387252F948A00CD03C3 /* Formatter.h */; }; + 93AE238A252F948A00CD03C3 /* Formatter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93AE2388252F948A00CD03C3 /* Formatter.cpp */; }; 93CBA4C020A74FF200867D56 /* BitmapReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93CBA4BF20A74FF200867D56 /* BitmapReader.cpp */; }; 93CBA4C320A7502E00867D56 /* Imaging.h in Headers */ = {isa = PBXBuildFile; fileRef = 93CBA4C120A7502D00867D56 /* Imaging.h */; }; 93CBA4C420A7502E00867D56 /* Imaging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93CBA4C220A7502E00867D56 /* Imaging.cpp */; }; @@ -1322,6 +1324,8 @@ 939A359D20C12FDD00630B3F /* Paint.Surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Paint.Surface.h; sourceTree = ""; }; 939A359E20C12FDE00630B3F /* Paint.TileElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Paint.TileElement.h; sourceTree = ""; }; 939A35A120C12FFD00630B3F /* InteractiveConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteractiveConsole.h; sourceTree = ""; }; + 93AE2387252F948A00CD03C3 /* Formatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Formatter.h; sourceTree = ""; }; + 93AE2388252F948A00CD03C3 /* Formatter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Formatter.cpp; sourceTree = ""; }; 93CBA4BE20A74FF200867D56 /* BitmapReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitmapReader.h; sourceTree = ""; }; 93CBA4BF20A74FF200867D56 /* BitmapReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitmapReader.cpp; sourceTree = ""; }; 93CBA4C120A7502D00867D56 /* Imaging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Imaging.h; sourceTree = ""; }; @@ -2938,6 +2942,8 @@ 4C7B53AE1FFF935B00A52E21 /* Date.h */, 4C7B53AF1FFF935B00A52E21 /* FormatCodes.cpp */, 4C7B53B01FFF935B00A52E21 /* FormatCodes.h */, + 93AE2388252F948A00CD03C3 /* Formatter.cpp */, + 93AE2387252F948A00CD03C3 /* Formatter.h */, 4C7B53B11FFF935B00A52E21 /* Language.cpp */, 4C7B53C91FFF991000A52E21 /* Language.h */, 4C7B53B31FFF935B00A52E21 /* LanguagePack.cpp */, @@ -3708,6 +3714,7 @@ 2ADE2F2B224418B2002598AF /* JobPool.hpp in Headers */, 2ADE2F3622441960002598AF /* RideTypes.h in Headers */, 93DFD05324521C1A001FCBAF /* ScRide.hpp in Headers */, + 93AE2389252F948A00CD03C3 /* Formatter.h in Headers */, 93DFD05424521C1A001FCBAF /* ScDate.hpp in Headers */, 93FC08FF2418F3ED00CA3054 /* duktape.h in Headers */, 93DFD04F24521C1A001FCBAF /* ScConsole.hpp in Headers */, @@ -4182,6 +4189,7 @@ C688786820289A4A0084B384 /* Util.cpp in Sources */, C688792720289B9B0084B384 /* TopSpin.cpp in Sources */, C688787E20289ADE0084B384 /* Drawing.cpp in Sources */, + 93AE238A252F948A00CD03C3 /* Formatter.cpp in Sources */, C68878A120289B200084B384 /* Localisation.cpp in Sources */, C68878ED20289B9B0084B384 /* BobsleighCoaster.cpp in Sources */, C688785E20289A0A0084B384 /* Fountain.cpp in Sources */, diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index c8a0862680..ddc47ec8d0 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -5787,7 +5787,7 @@ static void window_ride_graphs_update(rct_window* w) if (ride != nullptr) { RideMeasurement* measurement{}; - std::tie(measurement, std::ignore) = ride_get_measurement(ride); + std::tie(measurement, std::ignore) = ride->GetMeasurement(); x = measurement == nullptr ? 0 : measurement->current_item - ((widget->width() / 4) * 3); } } @@ -5812,7 +5812,7 @@ static void window_ride_graphs_scrollgetheight(rct_window* w, int32_t scrollInde if (ride != nullptr) { RideMeasurement* measurement{}; - std::tie(measurement, std::ignore) = ride_get_measurement(ride); + std::tie(measurement, std::ignore) = ride->GetMeasurement(); if (measurement != nullptr) { *width = std::max(*width, measurement->num_items); @@ -5840,7 +5840,7 @@ static void window_ride_graphs_tooltip(rct_window* w, rct_widgetindex widgetInde auto ride = get_ride(w->number); if (ride != nullptr) { - auto [measurement, message] = ride_get_measurement(ride); + auto [measurement, message] = ride->GetMeasurement(); if (measurement != nullptr && (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING)) { auto ft = Formatter::Common(); @@ -5850,7 +5850,7 @@ static void window_ride_graphs_tooltip(rct_window* w, rct_widgetindex widgetInde } else { - *stringId = message; + *stringId = message.str; } } } @@ -5941,19 +5941,20 @@ static void window_ride_graphs_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi gfx_clear(dpi, ColourMapA[COLOUR_SATURATED_GREEN].darker); auto widget = &window_ride_graphs_widgets[WIDX_GRAPH]; - auto stringId = STR_NONE; - RideMeasurement* measurement{}; auto ride = get_ride(w->number); - if (ride != nullptr) + if (ride == nullptr) { - std::tie(measurement, stringId) = ride_get_measurement(ride); + return; } + + auto [measurement, message] = ride->GetMeasurement(); + if (measurement == nullptr) { // No measurement message ScreenCoordsXY stringCoords(widget->width() / 2, widget->height() / 2 - 5); int32_t width = widget->width() - 2; - gfx_draw_string_centred_wrapped(dpi, gCommonFormatArgs, stringCoords, width, stringId, COLOUR_BLACK); + gfx_draw_string_centred_wrapped(dpi, message.args.Data(), stringCoords, width, message.str, COLOUR_BLACK); return; } diff --git a/src/openrct2/actions/RideSetStatus.hpp b/src/openrct2/actions/RideSetStatus.hpp index c0c796637c..ca7298d005 100644 --- a/src/openrct2/actions/RideSetStatus.hpp +++ b/src/openrct2/actions/RideSetStatus.hpp @@ -184,7 +184,7 @@ public: ride->race_winner = SPRITE_INDEX_NULL; ride->current_issues = 0; ride->last_issue_time = 0; - ride_get_measurement(ride); + ride->GetMeasurement(); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; window_invalidate_by_number(WC_RIDE, _rideIndex); break; @@ -231,7 +231,7 @@ public: ride->status = _status; ride->current_issues = 0; ride->last_issue_time = 0; - ride_get_measurement(ride); + ride->GetMeasurement(); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; window_invalidate_by_number(WC_RIDE, _rideIndex); break; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 762f7cf5c6..ff0794e8c5 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -219,6 +219,7 @@ + @@ -546,6 +547,7 @@ + @@ -775,4 +777,4 @@ - + \ No newline at end of file diff --git a/src/openrct2/localisation/Formatter.cpp b/src/openrct2/localisation/Formatter.cpp new file mode 100644 index 0000000000..bbaf27655f --- /dev/null +++ b/src/openrct2/localisation/Formatter.cpp @@ -0,0 +1,33 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "Formatter.h" + +thread_local uint8_t gCommonFormatArgs[80]; + +Formatter& Formatter::operator=(const Formatter& other) +{ + // If using global or not + if (other.StartBuf == other.Buffer.data()) + { + std::copy(std::begin(other.Buffer), std::end(other.Buffer), std::begin(Buffer)); + StartBuf = Buffer.data(); + } + else + { + StartBuf = other.StartBuf; + } + CurrentBuf = StartBuf + other.NumBytes(); + return *this; +} + +Formatter Formatter::Common() +{ + return Formatter{ gCommonFormatArgs }; +} diff --git a/src/openrct2/localisation/Formatter.h b/src/openrct2/localisation/Formatter.h new file mode 100644 index 0000000000..70610b1eaf --- /dev/null +++ b/src/openrct2/localisation/Formatter.h @@ -0,0 +1,112 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../common.h" + +#include +#include + +extern thread_local uint8_t gCommonFormatArgs[80]; + +class Formatter +{ + std::array Buffer{}; + uint8_t* StartBuf{}; + uint8_t* CurrentBuf{}; + +public: + explicit Formatter(uint8_t* buf) + : StartBuf(buf) + , CurrentBuf(buf) + { + } + + Formatter() + : Buffer{} + , StartBuf(Buffer.data()) + , CurrentBuf(StartBuf) + { + } + + Formatter(const Formatter& other) + { + *this = other; + } + + Formatter& operator=(const Formatter& other); + + static Formatter Common(); + + auto Buf() + { + return CurrentBuf; + } + + auto Data() const + { + return StartBuf; + } + + void Increment(size_t count) + { + CurrentBuf += count; + } + + void Rewind() + { + CurrentBuf -= NumBytes(); + } + + std::size_t NumBytes() const + { + return CurrentBuf - StartBuf; + } + + template Formatter& Add(TDeduced value) + { + static_assert(sizeof(TSpecified) <= sizeof(uintptr_t), "Type too large"); + static_assert(sizeof(TDeduced) <= sizeof(uintptr_t), "Type too large"); + + // clang-format off + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v + ); + // clang-format on + + uintptr_t convertedValue; + if constexpr (std::is_integral_v) + { + convertedValue = static_cast(value); + } + else + { + convertedValue = reinterpret_cast(value); + } + std::memcpy(CurrentBuf, &convertedValue, sizeof(TSpecified)); + Increment(sizeof(TSpecified)); + return *this; + } +}; + +struct OpenRCT2String +{ + rct_string_id str; + Formatter args; +}; diff --git a/src/openrct2/localisation/Localisation.cpp b/src/openrct2/localisation/Localisation.cpp index 941ac80136..51b798335b 100644 --- a/src/openrct2/localisation/Localisation.cpp +++ b/src/openrct2/localisation/Localisation.cpp @@ -37,7 +37,6 @@ #include thread_local char gCommonStringFormatBuffer[512]; -thread_local uint8_t gCommonFormatArgs[80]; #ifdef DEBUG // Set to true before a string format call to see details of the formatting. diff --git a/src/openrct2/localisation/Localisation.h b/src/openrct2/localisation/Localisation.h index bdf3ac4e8d..5b325242c5 100644 --- a/src/openrct2/localisation/Localisation.h +++ b/src/openrct2/localisation/Localisation.h @@ -17,8 +17,6 @@ #include "Language.h" #include "StringIds.h" -#include -#include #include bool utf8_is_format_code(char32_t codepoint); @@ -67,7 +65,6 @@ extern const char real_name_initials[16]; extern const char* real_names[1024]; extern thread_local char gCommonStringFormatBuffer[512]; -extern thread_local uint8_t gCommonFormatArgs[80]; extern bool gDebugStringFormatting; extern const rct_string_id SpeedNames[5]; @@ -80,110 +77,4 @@ extern const rct_string_id DateDayNames[31]; extern const rct_string_id DateGameMonthNames[MONTH_COUNT]; extern const rct_string_id DateGameShortMonthNames[MONTH_COUNT]; -class Formatter -{ - std::array Buffer{}; - uint8_t* StartBuf{}; - uint8_t* CurrentBuf{}; - -public: - explicit Formatter(uint8_t* buf) - : StartBuf(buf) - , CurrentBuf(buf) - { - } - - Formatter() - : Buffer{} - , StartBuf(Buffer.data()) - , CurrentBuf(StartBuf) - { - } - - Formatter(const Formatter& other) - { - *this = other; - } - - Formatter& operator=(const Formatter& other) - { - // If using global or not - if (other.StartBuf == other.Buffer.data()) - { - std::copy(std::begin(other.Buffer), std::end(other.Buffer), std::begin(Buffer)); - StartBuf = Buffer.data(); - } - else - { - StartBuf = other.StartBuf; - } - CurrentBuf = StartBuf + other.NumBytes(); - return *this; - } - - static Formatter Common() - { - return Formatter{ gCommonFormatArgs }; - } - - auto Buf() - { - return CurrentBuf; - } - - auto Data() const - { - return StartBuf; - } - - void Increment(size_t count) - { - CurrentBuf += count; - } - - void Rewind() - { - CurrentBuf -= NumBytes(); - } - - std::size_t NumBytes() const - { - return CurrentBuf - StartBuf; - } - - template Formatter& Add(TDeduced value) - { - static_assert(sizeof(TSpecified) <= sizeof(uintptr_t), "Type too large"); - static_assert(sizeof(TDeduced) <= sizeof(uintptr_t), "Type too large"); - - // clang-format off - static_assert( - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v - ); - // clang-format on - - uintptr_t convertedValue; - if constexpr (std::is_integral_v) - { - convertedValue = static_cast(value); - } - else - { - convertedValue = reinterpret_cast(value); - } - std::memcpy(CurrentBuf, &convertedValue, sizeof(TSpecified)); - Increment(sizeof(TSpecified)); - return *this; - } -}; - #endif diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 6240d86470..30d3b0a352 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -3008,38 +3008,37 @@ static void ride_free_old_measurements() } while (numRideMeasurements > MAX_RIDE_MEASUREMENTS); } -std::pair ride_get_measurement(Ride* ride) +std::pair Ride::GetMeasurement() { // Check if ride type supports data logging - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) + if (!ride_type_has_flag(type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) { - return { nullptr, STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE }; + return { nullptr, { STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE, {} } }; } // Check if a measurement already exists for this ride - auto& measurement = ride->measurement; if (measurement == nullptr) { measurement = std::make_unique(); - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) + if (ride_type_has_flag(type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { measurement->flags |= RIDE_MEASUREMENT_FLAG_G_FORCES; } ride_free_old_measurements(); - assert(ride->measurement != nullptr); + assert(measurement != nullptr); } measurement->last_use_tick = gScenarioTicks; if (measurement->flags & 1) { - return { measurement.get(), STR_EMPTY }; + return { measurement.get(), { STR_EMPTY, {} } }; } else { - auto ft = Formatter::Common(); - ft.Add(RideComponentNames[RideTypeDescriptors[ride->type].NameConvention.vehicle].singular); - ft.Add(RideComponentNames[RideTypeDescriptors[ride->type].NameConvention.station].singular); - return { nullptr, STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES }; + auto ft = Formatter(); + ft.Add(RideComponentNames[RideTypeDescriptors[type].NameConvention.vehicle].singular); + ft.Add(RideComponentNames[RideTypeDescriptors[type].NameConvention.station].singular); + return { nullptr, { STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES, ft } }; } } diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 9f65e4949e..b2deeeca3f 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -11,6 +11,7 @@ #define _RIDE_H_ #include "../common.h" +#include "../localisation/Formatter.h" #include "../rct12/RCT12.h" #include "../rct2/RCT2.h" #include "../world/Map.h" @@ -433,6 +434,8 @@ public: uint64_t GetAvailableModes() const; const RideTypeDescriptor& GetRideTypeDescriptor() const; TrackElement* GetOriginElement(StationIndex stationIndex) const; + + std::pair GetMeasurement(); }; #pragma pack(push, 1) @@ -1108,7 +1111,6 @@ vehicle_colour ride_get_vehicle_colour(Ride* ride, int32_t vehicleIndex); int32_t ride_get_unused_preset_vehicle_colour(uint8_t ride_sub_type); void ride_set_vehicle_colours_to_random_preset(Ride* ride, uint8_t preset_index); void ride_measurements_update(); -std::pair ride_get_measurement(Ride* ride); void ride_breakdown_add_news_item(Ride* ride); Peep* ride_find_closest_mechanic(Ride* ride, int32_t forInspection); int32_t ride_is_valid_for_open(Ride* ride, int32_t goingToBeOpen, bool isApplying);