From 6a42a954955d1fb2847b86287d84cb47fb469a68 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 13:49:46 +0100 Subject: [PATCH 1/9] Refactor random engine Introduce RotateEngine and Rct2Engine, FixedSeedSequence and Rct2Seed. Adhere respectively to requirements `RandomNumberEngine` and `SeedSequence`. Can be used with C++11 adaptors and distributions in . --- src/openrct2/core/Random.hpp | 175 +++++++++++++++++++++++++++++ src/openrct2/network/Network.cpp | 4 +- src/openrct2/rct1/S4Importer.cpp | 3 +- src/openrct2/rct2/S6Exporter.cpp | 4 +- src/openrct2/rct2/S6Importer.cpp | 5 +- src/openrct2/scenario/Scenario.cpp | 31 +++-- src/openrct2/scenario/Scenario.h | 4 +- test/tests/Pathfinding.cpp | 3 +- 8 files changed, 208 insertions(+), 21 deletions(-) create mode 100644 src/openrct2/core/Random.hpp diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp new file mode 100644 index 0000000000..70c34afe40 --- /dev/null +++ b/src/openrct2/core/Random.hpp @@ -0,0 +1,175 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 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 "Numerics.hpp" + +#include +#include +#include +#include +#include +#include + +namespace Random +{ + using namespace Numerics; + + /** + * FixedSeedSequence adheres to the _Named Requirement_ `SeedSequence`. + */ + template class FixedSeedSequence + { + public: + typedef uint32_t result_type; + + static constexpr size_t N = _N; + static constexpr result_type default_seed = 0x1234567F; + + explicit FixedSeedSequence() + { + std::fill(v.begin(), v.end(), default_seed); + } + + template< + typename... T, typename std::enable_if::type = 0, + typename std::enable_if<(std::is_convertible::value && ...), int>::type = 0> + explicit FixedSeedSequence(T... s) + : v{ static_cast(s)... } + { + } + + template(), ++std::declval<_It&>(), void())> + explicit FixedSeedSequence(_It begin, _It end) + { + std::copy(begin, end, v.begin()); + } + + template + explicit FixedSeedSequence(std::initializer_list il) + : FixedSeedSequence(il.begin(), il.end()) + { + } + + template void generate(_It begin, _It end) + { + std::copy_n(v.begin(), std::min((size_t)(end - begin), N), begin); + } + + constexpr size_t size() const + { + return N; + } + + template constexpr void param(_It ob) const + { + std::copy(v.begin(), v.end(), ob); + } + + protected: + std::array v; + }; + + typedef FixedSeedSequence<2> Rct2Seed; + + /** + * RotateEngine adheres to the _Named Requirement_ `RandomNumberEngine` + * https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine + */ + template class RotateEngine + { + static_assert(std::is_unsigned::value, "Type must be unsigned integral."); + + public: + typedef UIntType result_type; + static constexpr result_type x = __x; + static constexpr size_t r1 = __r1; + static constexpr size_t r2 = __r2; + static constexpr result_type default_seed = 1; + + static constexpr result_type min() + { + return std::numeric_limits::min(); + } + + static constexpr result_type max() + { + return std::numeric_limits::max(); + } + + explicit RotateEngine(result_type seed_value = default_seed) + { + seed(seed_value); + } + + RotateEngine(RotateEngine& r) + { + s0 = r.s0; + s1 = r.s1; + } + + template::value>::type> + explicit RotateEngine(Sseq& seed_seq) + { + seed(seed_seq); + } + + void seed(result_type s = default_seed) + { + s0 = s; + } + + template typename std::enable_if::value, void>::type seed(Sseq& seed_seq) + { + std::array s; + seed_seq.generate(s.begin(), s.end()); + s0 = s[0]; + s1 = s[1]; + } + + void discard(size_t n) + { + for (; n > 0; n--) + (*this)(); + } + result_type operator()() + { + auto s0z = s0; + s0 += ror(s1 ^ x, r1); + s1 = ror(s0z, r2); + return s1; + } + + friend bool operator==(const RotateEngine& lhs, const RotateEngine& rhs) + { + return lhs.s0 == rhs.s0 && lhs.s1 == rhs.s1; + } + + friend std::ostream& operator<<(std::ostream& os, const RotateEngine& e) + { + os << e.s0 << ' ' << e.s1; + return os; + } + + friend std::istream& operator>>(std::istream& is, RotateEngine& e) + { + is >> e.s0; + is >> e.s1; + return is; + } + + protected: + result_type s0; + result_type s1; + }; + + typedef RotateEngine Rct2Engine; + +} // namespace Random diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index a22858af7d..d23a648668 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -960,7 +960,7 @@ bool Network::CheckSRAND(uint32_t tick, uint32_t srand0) void Network::CheckDesynchronizaton() { // Check synchronisation - if (GetMode() == NETWORK_MODE_CLIENT && !_desynchronised && !CheckSRAND(gCurrentTicks, gScenarioSrand0)) + if (GetMode() == NETWORK_MODE_CLIENT && !_desynchronised && !CheckSRAND(gCurrentTicks, scenario_rand_seed().first)) { _desynchronised = true; @@ -1596,7 +1596,7 @@ void Network::Server_Send_TICK() last_tick_sent_time = ticks; std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << (uint32_t)NETWORK_COMMAND_TICK << gCurrentTicks << gScenarioSrand0; + *packet << (uint32_t)NETWORK_COMMAND_TICK << gCurrentTicks << scenario_rand_seed().first; uint32_t flags = 0; // Simple counter which limits how often a sprite checksum gets sent. // This can get somewhat expensive, so we don't want to push it every tick in release, diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index b8e3e858a2..fe18d67081 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -2451,8 +2451,7 @@ private: { // Date and srand gScenarioTicks = _s4.ticks; - gScenarioSrand0 = _s4.random_a; - gScenarioSrand1 = _s4.random_b; + scenario_rand_seed(_s4.random_a, _s4.random_b); gDateMonthsElapsed = _s4.month; gDateMonthTicks = _s4.day; diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 25fa6e70be..266608047b 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -188,8 +188,8 @@ void S6Exporter::Export() _s6.elapsed_months = gDateMonthsElapsed; _s6.current_day = gDateMonthTicks; _s6.scenario_ticks = gScenarioTicks; - _s6.scenario_srand_0 = gScenarioSrand0; - _s6.scenario_srand_1 = gScenarioSrand1; + + std::tie(_s6.scenario_srand_0, _s6.scenario_srand_1) = scenario_rand_seed(); std::memcpy(_s6.tile_elements, gTileElements, sizeof(_s6.tile_elements)); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index fad31af4ba..2015a30951 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -17,6 +17,7 @@ #include "../core/FileStream.hpp" #include "../core/IStream.hpp" #include "../core/Path.hpp" +#include "../core/Random.hpp" #include "../core/String.hpp" #include "../interface/Viewport.h" #include "../localisation/Date.h" @@ -207,8 +208,8 @@ public: gDateMonthsElapsed = _s6.elapsed_months; gDateMonthTicks = _s6.current_day; gScenarioTicks = _s6.scenario_ticks; - gScenarioSrand0 = _s6.scenario_srand_0; - gScenarioSrand1 = _s6.scenario_srand_1; + + scenario_rand_seed(_s6.scenario_srand_0, _s6.scenario_srand_1); ImportTileElements(); diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index eaa6bf5862..5ef2424669 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -18,6 +18,7 @@ #include "../ParkImporter.h" #include "../audio/audio.h" #include "../config/Config.h" +#include "../core/Random.hpp" #include "../interface/Viewport.h" #include "../localisation/Date.h" #include "../localisation/Localisation.h" @@ -48,6 +49,7 @@ #include "ScenarioSources.h" #include +#include const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = { STR_BEGINNER_PARKS, STR_CHALLENGING_PARKS, STR_EXPERT_PARKS, STR_REAL_PARKS, STR_OTHER_PARKS, @@ -66,8 +68,7 @@ uint16_t gSavedAge; uint32_t gLastAutoSaveUpdate = 0; uint32_t gScenarioTicks; -uint32_t gScenarioSrand0; -uint32_t gScenarioSrand1; +static Random::Rct2Engine rnd; uint8_t gScenarioObjectiveType; uint8_t gScenarioObjectiveYear; @@ -90,8 +91,8 @@ void scenario_begin() game_load_init(); // Set the scenario pseudo-random seeds - gScenarioSrand0 ^= platform_get_ticks(); - gScenarioSrand1 ^= platform_get_ticks(); + Random::Rct2Seed s{ 0x1234567F ^ platform_get_ticks(), 0x789FABCD ^ platform_get_ticks() }; + rnd.seed(s); gParkFlags &= ~PARK_FLAGS_NO_MONEY; if (gParkFlags & PARK_FLAGS_NO_MONEY_SCENARIO) @@ -476,6 +477,22 @@ static int32_t scenario_create_ducks() return 1; } +std::pair scenario_rand_seed() +{ + std::stringstream ss; + ss << rnd; + uint32_t s0, s1; + ss >> s0; + ss >> s1; + return { s0, s1 }; +}; + +void scenario_rand_seed(uint32_t s0, uint32_t s1) +{ + Random::Rct2Seed s{ s0, s1 }; + rnd.seed(s); +} + /** * * rct2: 0x006E37D2 @@ -491,10 +508,6 @@ static const char* realm = "LC"; uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_t line, const void* data) #endif { - uint32_t originalSrand0 = gScenarioSrand0; - gScenarioSrand0 += ror32(gScenarioSrand1 ^ 0x1234567F, 7); - gScenarioSrand1 = ror32(originalSrand0, 3); - #ifdef DEBUG_DESYNC if (fp == nullptr) { @@ -527,7 +540,7 @@ uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_ } #endif - return gScenarioSrand1; + return rnd(); } #ifdef DEBUG_DESYNC diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 0e5966794e..186e9f8c10 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -366,8 +366,6 @@ enum extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; extern uint32_t gScenarioTicks; -extern uint32_t gScenarioSrand0; -extern uint32_t gScenarioSrand1; extern uint8_t gScenarioObjectiveType; extern uint8_t gScenarioObjectiveYear; @@ -394,6 +392,8 @@ void load_from_sc6(const char* path); void scenario_begin(); void scenario_update(); +std::pair scenario_rand_seed(); +void scenario_rand_seed(uint32_t s0, uint32_t s1); #ifdef DEBUG_DESYNC uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_t line, const void* data); # define scenario_rand() dbg_scenario_rand(__FILE__, __FUNCTION__, __LINE__, NULL) diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index 43a99654df..2bcca46322 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -41,8 +41,7 @@ public: void SetUp() override { // Use a consistent random seed in every test - gScenarioSrand0 = 0x12345678; - gScenarioSrand1 = 0x87654321; + scenario_rand_seed(0x12345678, 0x87654321); } static void TearDownTestCase() From 1a81d6060945f17fd2d47fb2f77485b12534bab8 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 14:48:40 +0100 Subject: [PATCH 2/9] Expose gScenarioRand, add --- src/openrct2/core/Random.hpp | 1 + src/openrct2/scenario/Scenario.cpp | 10 +++++----- src/openrct2/scenario/Scenario.h | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index 70c34afe40..91254c577d 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -11,6 +11,7 @@ #include "Numerics.hpp" +#include #include #include #include diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 5ef2424669..b806b3ddb0 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -68,7 +68,7 @@ uint16_t gSavedAge; uint32_t gLastAutoSaveUpdate = 0; uint32_t gScenarioTicks; -static Random::Rct2Engine rnd; +Random::Rct2Engine gScenarioRand; uint8_t gScenarioObjectiveType; uint8_t gScenarioObjectiveYear; @@ -92,7 +92,7 @@ void scenario_begin() // Set the scenario pseudo-random seeds Random::Rct2Seed s{ 0x1234567F ^ platform_get_ticks(), 0x789FABCD ^ platform_get_ticks() }; - rnd.seed(s); + gScenarioRand.seed(s); gParkFlags &= ~PARK_FLAGS_NO_MONEY; if (gParkFlags & PARK_FLAGS_NO_MONEY_SCENARIO) @@ -480,7 +480,7 @@ static int32_t scenario_create_ducks() std::pair scenario_rand_seed() { std::stringstream ss; - ss << rnd; + ss << gScenarioRand; uint32_t s0, s1; ss >> s0; ss >> s1; @@ -490,7 +490,7 @@ std::pair scenario_rand_seed() void scenario_rand_seed(uint32_t s0, uint32_t s1) { Random::Rct2Seed s{ s0, s1 }; - rnd.seed(s); + gScenarioRand.seed(s); } /** @@ -540,7 +540,7 @@ uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_ } #endif - return rnd(); + return gScenarioRand(); } #ifdef DEBUG_DESYNC diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 186e9f8c10..94936e64d6 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -11,6 +11,7 @@ #define _SCENARIO_H_ #include "../common.h" +#include "../core/Random.hpp" #include "../management/Finance.h" #include "../management/Research.h" #include "../object/Object.h" @@ -366,6 +367,7 @@ enum extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; extern uint32_t gScenarioTicks; +extern Random::Rct2Engine gScenarioRand; extern uint8_t gScenarioObjectiveType; extern uint8_t gScenarioObjectiveYear; From 2ea347f15f193e8c91a42b5f8473d1c973b798a2 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 15:50:09 +0100 Subject: [PATCH 3/9] MSVC SFINAE compatibility --- src/openrct2/core/Meta.hpp | 30 ++++++++++++++++++++++++++++++ src/openrct2/core/Random.hpp | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/openrct2/core/Meta.hpp diff --git a/src/openrct2/core/Meta.hpp b/src/openrct2/core/Meta.hpp new file mode 100644 index 0000000000..2293e8ae88 --- /dev/null +++ b/src/openrct2/core/Meta.hpp @@ -0,0 +1,30 @@ +/***************************************************************************** + * Copyright (c) 2014-2019 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 + +namespace Meta +{ + /** + * Meta function for checking that all Conditions are true types. + */ + template struct all : std::true_type + { + }; + + template + struct all : std::conditional, std::false_type>::type + { + }; + + template using all_convertible = all...>; + +} // namespace Meta diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index 91254c577d..ca0088ca55 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -9,6 +9,7 @@ #pragma once +#include "Meta.hpp" #include "Numerics.hpp" #include @@ -41,7 +42,7 @@ namespace Random template< typename... T, typename std::enable_if::type = 0, - typename std::enable_if<(std::is_convertible::value && ...), int>::type = 0> + typename std::enable_if::value, int>::type = 0> explicit FixedSeedSequence(T... s) : v{ static_cast(s)... } { From 16691b22baaa8a9bd0e6449be8b98e567184f393 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 19:29:43 +0100 Subject: [PATCH 4/9] Use state struct --- src/openrct2/core/Random.hpp | 24 +++++++++++++++++++----- src/openrct2/network/Network.cpp | 4 ++-- src/openrct2/rct2/S6Exporter.cpp | 4 +++- src/openrct2/scenario/Scenario.cpp | 13 ++++--------- src/openrct2/scenario/Scenario.h | 10 ++++++---- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index ca0088ca55..eea44ee9bc 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -81,16 +81,28 @@ namespace Random typedef FixedSeedSequence<2> Rct2Seed; + template struct RotateEngineState + { + UIntType s0; + UIntType s1; + }; + /** * RotateEngine adheres to the _Named Requirement_ `RandomNumberEngine` * https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine */ - template class RotateEngine + template + class RotateEngine : protected RotateEngineState { static_assert(std::is_unsigned::value, "Type must be unsigned integral."); + using RotateEngineState::s0; + using RotateEngineState::s1; + public: typedef UIntType result_type; + typedef RotateEngineState state_type; + static constexpr result_type x = __x; static constexpr size_t r1 = __r1; static constexpr size_t r2 = __r2; @@ -126,6 +138,7 @@ namespace Random void seed(result_type s = default_seed) { s0 = s; + s1 = s; } template typename std::enable_if::value, void>::type seed(Sseq& seed_seq) @@ -154,6 +167,11 @@ namespace Random return lhs.s0 == rhs.s0 && lhs.s1 == rhs.s1; } + const state_type& state() const + { + return *this; + } + friend std::ostream& operator<<(std::ostream& os, const RotateEngine& e) { os << e.s0 << ' ' << e.s1; @@ -166,10 +184,6 @@ namespace Random is >> e.s1; return is; } - - protected: - result_type s0; - result_type s1; }; typedef RotateEngine Rct2Engine; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index d23a648668..91df04ba10 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -960,7 +960,7 @@ bool Network::CheckSRAND(uint32_t tick, uint32_t srand0) void Network::CheckDesynchronizaton() { // Check synchronisation - if (GetMode() == NETWORK_MODE_CLIENT && !_desynchronised && !CheckSRAND(gCurrentTicks, scenario_rand_seed().first)) + if (GetMode() == NETWORK_MODE_CLIENT && !_desynchronised && !CheckSRAND(gCurrentTicks, scenario_rand_state().s0)) { _desynchronised = true; @@ -1596,7 +1596,7 @@ void Network::Server_Send_TICK() last_tick_sent_time = ticks; std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << (uint32_t)NETWORK_COMMAND_TICK << gCurrentTicks << scenario_rand_seed().first; + *packet << (uint32_t)NETWORK_COMMAND_TICK << gCurrentTicks << scenario_rand_state().s0; uint32_t flags = 0; // Simple counter which limits how often a sprite checksum gets sent. // This can get somewhat expensive, so we don't want to push it every tick in release, diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 266608047b..a44f43f279 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -189,7 +189,9 @@ void S6Exporter::Export() _s6.current_day = gDateMonthTicks; _s6.scenario_ticks = gScenarioTicks; - std::tie(_s6.scenario_srand_0, _s6.scenario_srand_1) = scenario_rand_seed(); + auto state = scenario_rand_state(); + _s6.scenario_srand_0 = state.s0; + _s6.scenario_srand_1 = state.s1; std::memcpy(_s6.tile_elements, gTileElements, sizeof(_s6.tile_elements)); diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index b806b3ddb0..3a45ca5375 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -477,17 +477,12 @@ static int32_t scenario_create_ducks() return 1; } -std::pair scenario_rand_seed() +const random_engine_t::state_type& scenario_rand_state() { - std::stringstream ss; - ss << gScenarioRand; - uint32_t s0, s1; - ss >> s0; - ss >> s1; - return { s0, s1 }; + return gScenarioRand.state(); }; -void scenario_rand_seed(uint32_t s0, uint32_t s1) +void scenario_rand_seed(random_engine_t::result_type s0, random_engine_t::result_type s1) { Random::Rct2Seed s{ s0, s1 }; gScenarioRand.seed(s); @@ -500,7 +495,7 @@ void scenario_rand_seed(uint32_t s0, uint32_t s1) * @return eax */ #ifndef DEBUG_DESYNC -uint32_t scenario_rand() +random_engine_t::result_type scenario_rand() #else static FILE* fp = nullptr; static const char* realm = "LC"; diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 94936e64d6..992728208c 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -24,6 +24,8 @@ #include "../world/MapAnimation.h" #include "../world/Sprite.h" +using random_engine_t = Random::Rct2Engine; + struct ParkLoadResult; #pragma pack(push, 1) @@ -367,7 +369,7 @@ enum extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; extern uint32_t gScenarioTicks; -extern Random::Rct2Engine gScenarioRand; +extern random_engine_t gScenarioRand; extern uint8_t gScenarioObjectiveType; extern uint8_t gScenarioObjectiveYear; @@ -394,15 +396,15 @@ void load_from_sc6(const char* path); void scenario_begin(); void scenario_update(); -std::pair scenario_rand_seed(); -void scenario_rand_seed(uint32_t s0, uint32_t s1); +const random_engine_t::state_type& scenario_rand_state(); +void scenario_rand_seed(random_engine_t::result_type s0, random_engine_t::result_type s1); #ifdef DEBUG_DESYNC uint32_t dbg_scenario_rand(const char* file, const char* function, const uint32_t line, const void* data); # define scenario_rand() dbg_scenario_rand(__FILE__, __FUNCTION__, __LINE__, NULL) # define scenario_rand_data(data) dbg_scenario_rand(__FILE__, __FUNCTION__, __LINE__, data) void dbg_report_desync(uint32_t tick, uint32_t srand0, uint32_t server_srand0, const char* clientHash, const char* serverHash); #else -uint32_t scenario_rand(); +random_engine_t::result_type scenario_rand(); #endif uint32_t scenario_rand_max(uint32_t max); From dfe7f0614cc392f8db29133bdbbae6209c2ac641 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 21:00:12 +0100 Subject: [PATCH 5/9] Consistency --- src/openrct2/core/Random.hpp | 38 +++++++++++++++++------------- src/openrct2/scenario/Scenario.cpp | 6 ++--- src/openrct2/scenario/Scenario.h | 2 +- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index eea44ee9bc..60431abc37 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -27,12 +27,12 @@ namespace Random /** * FixedSeedSequence adheres to the _Named Requirement_ `SeedSequence`. */ - template class FixedSeedSequence + template class FixedSeedSequence { public: - typedef uint32_t result_type; + using result_type = uint32_t; - static constexpr size_t N = _N; + static constexpr size_t N = __N; static constexpr result_type default_seed = 0x1234567F; explicit FixedSeedSequence() @@ -60,7 +60,7 @@ namespace Random { } - template void generate(_It begin, _It end) + template void generate(_It begin, _It end) const { std::copy_n(v.begin(), std::min((size_t)(end - begin), N), begin); } @@ -79,12 +79,12 @@ namespace Random std::array v; }; - typedef FixedSeedSequence<2> Rct2Seed; - template struct RotateEngineState { - UIntType s0; - UIntType s1; + using value_type = UIntType; + + value_type s0; + value_type s1; }; /** @@ -100,8 +100,8 @@ namespace Random using RotateEngineState::s1; public: - typedef UIntType result_type; - typedef RotateEngineState state_type; + using result_type = UIntType; + using state_type = RotateEngineState; static constexpr result_type x = __x; static constexpr size_t r1 = __r1; @@ -162,16 +162,16 @@ namespace Random return s1; } - friend bool operator==(const RotateEngine& lhs, const RotateEngine& rhs) - { - return lhs.s0 == rhs.s0 && lhs.s1 == rhs.s1; - } - const state_type& state() const { return *this; } + friend bool operator==(const RotateEngine& lhs, const RotateEngine& rhs) + { + return lhs.s0 == rhs.s0 && lhs.s1 == rhs.s1; + } + friend std::ostream& operator<<(std::ostream& os, const RotateEngine& e) { os << e.s0 << ' ' << e.s1; @@ -186,6 +186,10 @@ namespace Random } }; - typedef RotateEngine Rct2Engine; - + namespace Rct2 + { + using Engine = RotateEngine; + using Seed = FixedSeedSequence<2>; + using State = Engine::state_type; + } // namespace Rct2 } // namespace Random diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 3a45ca5375..91f4e4ba96 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -68,7 +68,7 @@ uint16_t gSavedAge; uint32_t gLastAutoSaveUpdate = 0; uint32_t gScenarioTicks; -Random::Rct2Engine gScenarioRand; +random_engine_t gScenarioRand; uint8_t gScenarioObjectiveType; uint8_t gScenarioObjectiveYear; @@ -91,7 +91,7 @@ void scenario_begin() game_load_init(); // Set the scenario pseudo-random seeds - Random::Rct2Seed s{ 0x1234567F ^ platform_get_ticks(), 0x789FABCD ^ platform_get_ticks() }; + Random::Rct2::Seed s{ 0x1234567F ^ platform_get_ticks(), 0x789FABCD ^ platform_get_ticks() }; gScenarioRand.seed(s); gParkFlags &= ~PARK_FLAGS_NO_MONEY; @@ -484,7 +484,7 @@ const random_engine_t::state_type& scenario_rand_state() void scenario_rand_seed(random_engine_t::result_type s0, random_engine_t::result_type s1) { - Random::Rct2Seed s{ s0, s1 }; + Random::Rct2::Seed s{ s0, s1 }; gScenarioRand.seed(s); } diff --git a/src/openrct2/scenario/Scenario.h b/src/openrct2/scenario/Scenario.h index 992728208c..3b2a68188a 100644 --- a/src/openrct2/scenario/Scenario.h +++ b/src/openrct2/scenario/Scenario.h @@ -24,7 +24,7 @@ #include "../world/MapAnimation.h" #include "../world/Sprite.h" -using random_engine_t = Random::Rct2Engine; +using random_engine_t = Random::Rct2::Engine; struct ParkLoadResult; From ec8caa5636dd68de65b9a7ea030c3f89daa039a4 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 21:47:47 +0100 Subject: [PATCH 6/9] Drop --- src/openrct2/scenario/Scenario.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 91f4e4ba96..77fcdbbac7 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -49,7 +49,6 @@ #include "ScenarioSources.h" #include -#include const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = { STR_BEGINNER_PARKS, STR_CHALLENGING_PARKS, STR_EXPERT_PARKS, STR_REAL_PARKS, STR_OTHER_PARKS, From 1e65db371b67d4e87e9363cce75d8b9033777509 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 21:51:01 +0100 Subject: [PATCH 7/9] Use single underscore prefix for template parameters --- src/openrct2/core/Random.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index 60431abc37..2ba0da05fa 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -27,12 +27,12 @@ namespace Random /** * FixedSeedSequence adheres to the _Named Requirement_ `SeedSequence`. */ - template class FixedSeedSequence + template class FixedSeedSequence { public: using result_type = uint32_t; - static constexpr size_t N = __N; + static constexpr size_t N = _N; static constexpr result_type default_seed = 0x1234567F; explicit FixedSeedSequence() @@ -91,8 +91,7 @@ namespace Random * RotateEngine adheres to the _Named Requirement_ `RandomNumberEngine` * https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine */ - template - class RotateEngine : protected RotateEngineState + template class RotateEngine : protected RotateEngineState { static_assert(std::is_unsigned::value, "Type must be unsigned integral."); @@ -103,9 +102,9 @@ namespace Random using result_type = UIntType; using state_type = RotateEngineState; - static constexpr result_type x = __x; - static constexpr size_t r1 = __r1; - static constexpr size_t r2 = __r2; + static constexpr result_type x = _x; + static constexpr size_t r1 = _r1; + static constexpr size_t r2 = _r2; static constexpr result_type default_seed = 1; static constexpr result_type min() From 422d5f2ef1f20de285ccc485b5c5aaea3168edab Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Fri, 1 Feb 2019 21:54:00 +0100 Subject: [PATCH 8/9] Replace '_N' by '_num' --- src/openrct2/core/Random.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index 2ba0da05fa..daab3291cf 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -27,12 +27,12 @@ namespace Random /** * FixedSeedSequence adheres to the _Named Requirement_ `SeedSequence`. */ - template class FixedSeedSequence + template class FixedSeedSequence { public: using result_type = uint32_t; - static constexpr size_t N = _N; + static constexpr size_t N = _num; static constexpr result_type default_seed = 0x1234567F; explicit FixedSeedSequence() From 045692993a1696c32a130604fca495c7fe7b12c1 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Sun, 3 Feb 2019 21:16:09 +0100 Subject: [PATCH 9/9] Make template params adhere to code style --- src/openrct2/core/Meta.hpp | 8 +++--- src/openrct2/core/Random.hpp | 51 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/openrct2/core/Meta.hpp b/src/openrct2/core/Meta.hpp index 2293e8ae88..b63d140f17 100644 --- a/src/openrct2/core/Meta.hpp +++ b/src/openrct2/core/Meta.hpp @@ -16,15 +16,15 @@ namespace Meta /** * Meta function for checking that all Conditions are true types. */ - template struct all : std::true_type + template struct all : std::true_type { }; - template - struct all : std::conditional, std::false_type>::type + template + struct all<_TCondition, _TConditions...> : std::conditional<_TCondition::value, all<_TConditions...>, std::false_type>::type { }; - template using all_convertible = all...>; + template using all_convertible = all...>; } // namespace Meta diff --git a/src/openrct2/core/Random.hpp b/src/openrct2/core/Random.hpp index daab3291cf..cdca9daa73 100644 --- a/src/openrct2/core/Random.hpp +++ b/src/openrct2/core/Random.hpp @@ -27,12 +27,12 @@ namespace Random /** * FixedSeedSequence adheres to the _Named Requirement_ `SeedSequence`. */ - template class FixedSeedSequence + template class FixedSeedSequence { public: using result_type = uint32_t; - static constexpr size_t N = _num; + static constexpr size_t N = _TNum; static constexpr result_type default_seed = 0x1234567F; explicit FixedSeedSequence() @@ -41,26 +41,26 @@ namespace Random } template< - typename... T, typename std::enable_if::type = 0, - typename std::enable_if::value, int>::type = 0> - explicit FixedSeedSequence(T... s) + typename... _TTypes, typename std::enable_if::type = 0, + typename std::enable_if::value, int>::type = 0> + explicit FixedSeedSequence(_TTypes... s) : v{ static_cast(s)... } { } - template(), ++std::declval<_It&>(), void())> - explicit FixedSeedSequence(_It begin, _It end) + template(), ++std::declval<_TIt&>(), void())> + explicit FixedSeedSequence(_TIt begin, _TIt end) { std::copy(begin, end, v.begin()); } - template - explicit FixedSeedSequence(std::initializer_list il) + template + explicit FixedSeedSequence(std::initializer_list<_TType> il) : FixedSeedSequence(il.begin(), il.end()) { } - template void generate(_It begin, _It end) const + template void generate(_TIt begin, _TIt end) const { std::copy_n(v.begin(), std::min((size_t)(end - begin), N), begin); } @@ -70,7 +70,7 @@ namespace Random return N; } - template constexpr void param(_It ob) const + template constexpr void param(_TIt ob) const { std::copy(v.begin(), v.end(), ob); } @@ -79,9 +79,9 @@ namespace Random std::array v; }; - template struct RotateEngineState + template struct RotateEngineState { - using value_type = UIntType; + using value_type = _TUIntType; value_type s0; value_type s1; @@ -91,20 +91,21 @@ namespace Random * RotateEngine adheres to the _Named Requirement_ `RandomNumberEngine` * https://en.cppreference.com/w/cpp/named_req/RandomNumberEngine */ - template class RotateEngine : protected RotateEngineState + template + class RotateEngine : protected RotateEngineState<_TUIntType> { - static_assert(std::is_unsigned::value, "Type must be unsigned integral."); + static_assert(std::is_unsigned<_TUIntType>::value, "Type must be unsigned integral."); - using RotateEngineState::s0; - using RotateEngineState::s1; + using RotateEngineState<_TUIntType>::s0; + using RotateEngineState<_TUIntType>::s1; public: - using result_type = UIntType; - using state_type = RotateEngineState; + using result_type = _TUIntType; + using state_type = RotateEngineState<_TUIntType>; - static constexpr result_type x = _x; - static constexpr size_t r1 = _r1; - static constexpr size_t r2 = _r2; + static constexpr result_type x = _TX; + static constexpr size_t r1 = _TR1; + static constexpr size_t r2 = _TR2; static constexpr result_type default_seed = 1; static constexpr result_type min() @@ -128,8 +129,8 @@ namespace Random s1 = r.s1; } - template::value>::type> - explicit RotateEngine(Sseq& seed_seq) + template::value>::type> + explicit RotateEngine(_TSseq& seed_seq) { seed(seed_seq); } @@ -140,7 +141,7 @@ namespace Random s1 = s; } - template typename std::enable_if::value, void>::type seed(Sseq& seed_seq) + template typename std::enable_if::value, void>::type seed(_TSseq& seed_seq) { std::array s; seed_seq.generate(s.begin(), s.end());