diff --git a/rwengine/src/ai/CharacterController.cpp b/rwengine/src/ai/CharacterController.cpp index d9171dc5..f6d413d7 100644 --- a/rwengine/src/ai/CharacterController.cpp +++ b/rwengine/src/ai/CharacterController.cpp @@ -342,8 +342,8 @@ bool Activities::DriveTo::update(CharacterObject *character, else if (potentialNodes.size() > 1) { // Choose the next node randomly if(nextTargetNode == nullptr) { - auto& random = character->engine->randomEngine; - auto i = std::uniform_int_distribution(0, potentialNodes.size() - 1)(random); + auto i = character->engine->getRandomNumber( + 0u, potentialNodes.size() - 1); nextTargetNode = potentialNodes.at(i); } diff --git a/rwengine/src/ai/DefaultAIController.cpp b/rwengine/src/ai/DefaultAIController.cpp index c443fc63..d447a0f2 100644 --- a/rwengine/src/ai/DefaultAIController.cpp +++ b/rwengine/src/ai/DefaultAIController.cpp @@ -2,7 +2,6 @@ #include #include -#include #include "ai/AIGraph.hpp" #include "ai/AIGraphNode.hpp" @@ -65,11 +64,9 @@ void DefaultAIController::update(float dt) { if (glm::length(targetDistance) <= 0.1f) { // Assign the next target node auto lastTarget = targetNode; - std::random_device rd; - std::default_random_engine re(rd()); - std::uniform_int_distribution d( - 0, lastTarget->connections.size() - 1); - targetNode = lastTarget->connections.at(d(re)); + targetNode = lastTarget->connections.at( + character->engine->getRandomNumber( + 0u, lastTarget->connections.size() - 1)); setNextActivity(std::make_unique( targetNode->position)); } else if (getCurrentActivity() == nullptr) { @@ -155,9 +152,9 @@ void DefaultAIController::update(float dt) { // If we haven't found a node, choose one randomly if (!targetNode) { - auto& random = getCharacter()->engine->randomEngine; - size_t nodeIndex = std::uniform_int_distribution(0, lastTargetNode->connections.size() - 1)(random); - targetNode = lastTargetNode->connections.at(nodeIndex); + targetNode = lastTargetNode->connections.at( + character->engine->getRandomNumber( + 0u, lastTargetNode->connections.size() - 1)); } // Check whether the maximum amount of lanes changed and adjust our lane diff --git a/rwengine/src/ai/TrafficDirector.cpp b/rwengine/src/ai/TrafficDirector.cpp index 45dd3acf..570f1743 100644 --- a/rwengine/src/ai/TrafficDirector.cpp +++ b/rwengine/src/ai/TrafficDirector.cpp @@ -94,7 +94,6 @@ void TrafficDirector::setDensity(AIGraphNode::NodeType type, float density) { std::vector TrafficDirector::populateNearby( const ViewCamera& camera, float radius, int maxSpawn) { - auto& random = world->randomEngine; std::vector created; /// @todo Check how "in player view" should be determined. @@ -169,8 +168,8 @@ std::vector TrafficDirector::populateNearby( counter--; // Spawn a pedestrian from the available pool - const auto pedId = static_cast( - peds[std::uniform_int_distribution(0, peds.size() - 1)(random)]); + const auto pedId = + peds.at(world->getRandomNumber(0u, peds.size() - 1)); auto ped = world->createPedestrian(pedId, spawn->position); ped->applyOffset(); ped->setLifetime(GameObject::TrafficLifetime); @@ -230,21 +229,21 @@ std::vector TrafficDirector::populateNearby( } // Choose a random lane - const int lane = - std::uniform_int_distribution<>(1, maxLanes)(random); + const int lane = world->getRandomNumber(1, maxLanes); const glm::vec3 laneOffset = strafe * (2.5f + 5.f * static_cast(lane - 1)); // Spawn a vehicle from the available pool - const auto carId = static_cast(cars[std::uniform_int_distribution( - 0, cars.size() - 1)(random)]); + const auto carId = + cars.at(world->getRandomNumber(0u, cars.size() - 1)); auto vehicle = world->createVehicle(carId, next->position + diff + laneOffset, orientation); vehicle->applyOffset(); vehicle->setLifetime(GameObject::TrafficLifetime); vehicle->setHandbraking(false); // Spawn a pedestrian and put it into the vehicle - const auto pedId = peds[std::uniform_int_distribution(0, peds.size() - 1)(random)]; + const auto pedId = + peds.at(world->getRandomNumber(0u, peds.size() - 1)); CharacterObject* character = world->createPedestrian(pedId, vehicle->getPosition()); character->setLifetime(GameObject::TrafficLifetime); character->setCurrentVehicle(vehicle, 0); diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index e93eb548..5e56472b 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -250,8 +250,7 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, auto palit = data->vehiclePalettes.find( vti->name); // modelname is conveniently lowercase (usually) if (palit != data->vehiclePalettes.end() && !palit->second.empty()) { - std::uniform_int_distribution uniform(0, palit->second.size() - 1); - size_t set = uniform(randomEngine); + size_t set = getRandomNumber(0u, palit->second.size() - 1); prim = data->vehicleColours[palit->second[set].first]; sec = data->vehicleColours[palit->second[set].second]; } else { diff --git a/rwengine/src/engine/GameWorld.hpp b/rwengine/src/engine/GameWorld.hpp index 12183619..ae7c17b6 100644 --- a/rwengine/src/engine/GameWorld.hpp +++ b/rwengine/src/engine/GameWorld.hpp @@ -320,11 +320,6 @@ public: */ std::vector> effects; - /** - * Randomness Engine - */ - std::default_random_engine randomEngine{std::random_device{}()}; - /** * Bullet */ @@ -405,6 +400,26 @@ public: PlayerController* getPlayer(); + template < + typename T1, typename T2 = T1, + typename std::enable_if::value>::type* = nullptr, + typename std::enable_if::value>::type* = nullptr> + T1 getRandomNumber(T1 min, T2 max) { + std::uniform_int_distribution dist(min, max); + return dist(randomNumberGen); + } + + template < + typename T1, typename T2 = T1, + typename std::enable_if::value>::type* = + nullptr, + typename std::enable_if::value>::type* = + nullptr> + T1 getRandomNumber(T1 min, T2 max) { + std::uniform_real_distribution dist(min, max); + return dist(randomNumberGen); + } + private: /** * @brief Used by objects to delete themselves during updates. @@ -422,6 +437,11 @@ private: * Private data */ std::unique_ptr _overlappingPairCallback; + + /** + * Randomness Engine + */ + std::default_random_engine randomNumberGen{std::random_device()()}; }; #endif diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 73b2c0e7..7e26cd22 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -232,7 +232,6 @@ void VehicleObject::setupModel() { if ((rule & 0xF00) == 0xF00) return 2; return 3; }; - auto& random = engine->randomEngine; while (compRules != 0) { auto rule = (compRules & 0xFFFF); auto type = static_cast(rule >> 12); @@ -243,12 +242,12 @@ void VehicleObject::setupModel() { case ComponentRuleType::Any: case ComponentRuleType::RainOnly: { auto max = numComponents(rule) - 1; - auto i = std::uniform_int_distribution<>(0, max)(random); + auto i = engine->getRandomNumber(0, max); result = (rule >> (4 * i)) & 0xF; } break; case ComponentRuleType::Optional: { auto max = numComponents(rule) - 1; - auto i = std::uniform_int_distribution<>(-1, max)(random); + auto i = engine->getRandomNumber(-1, max); if (i == -1) { break; } @@ -256,7 +255,7 @@ void VehicleObject::setupModel() { } break; case ComponentRuleType::Random: /// @todo this should fail to enable the 6th component - result = std::uniform_int_distribution<>(0, 5)(random); + result = engine->getRandomNumber(0, 5); break; } diff --git a/rwengine/src/script/ScriptMachine.cpp b/rwengine/src/script/ScriptMachine.cpp index 3b4b9d9b..0a3af8cf 100644 --- a/rwengine/src/script/ScriptMachine.cpp +++ b/rwengine/src/script/ScriptMachine.cpp @@ -191,8 +191,7 @@ ScriptMachine::ScriptMachine(GameState* _state, SCMFile& file, : file(file) , module(ops) , state(_state) - , debugFlag(false) - , randomNumberGen(std::random_device()()) { + , debugFlag(false) { // Copy globals auto size = file.getGlobalsSize(); globalData.resize(size); diff --git a/rwengine/src/script/ScriptMachine.hpp b/rwengine/src/script/ScriptMachine.hpp index cd1c4c08..ff3d0af6 100644 --- a/rwengine/src/script/ScriptMachine.hpp +++ b/rwengine/src/script/ScriptMachine.hpp @@ -164,20 +164,6 @@ public: debugFlag = flag; } - template - typename std::enable_if::value, T>::type - getRandomNumber(T min, T max) { - std::uniform_int_distribution dist(min, max); - return dist(randomNumberGen); - } - - template - typename std::enable_if::value, T>::type - getRandomNumber(T min, T max) { - std::uniform_real_distribution dist(min, max); - return dist(randomNumberGen); - } - /** * @brief executes threads until they are all in waiting state. */ @@ -194,8 +180,6 @@ private: void executeThread(SCMThread& t, int msPassed); std::vector globalData; - - std::mt19937 randomNumberGen; }; #endif diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index e27c1c10..e01ba039 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -1765,7 +1765,7 @@ void opcode_0097(const ScriptArguments& args, ScriptFloat& arg1L) { @arg arg1G */ void opcode_0098(const ScriptArguments& args, ScriptFloat& arg1G) { - arg1G = args.getVM()->getRandomNumber(0.f, 1.f); + arg1G = args.getWorld()->getRandomNumber(0.f, 1.f); } /** @@ -1776,7 +1776,7 @@ void opcode_0098(const ScriptArguments& args, ScriptFloat& arg1G) { */ void opcode_0099(const ScriptArguments& args, ScriptInt& arg1G) { // TODO: For GTA III and VC, the range is 0-65535, for GTA: SA it is 0-32767 - arg1G = args.getVM()->getRandomNumber(0, 65535); + arg1G = args.getWorld()->getRandomNumber(0, 65535); } /** @@ -5886,7 +5886,7 @@ bool opcode_0207(const ScriptArguments& args, const ScriptCharacter character, c @arg result */ void opcode_0208(const ScriptArguments& args, const ScriptFloat min, const ScriptFloat max, ScriptFloat& result) { - result = args.getVM()->getRandomNumber(min, max); + result = args.getWorld()->getRandomNumber(min, max); } /** @@ -5898,7 +5898,7 @@ void opcode_0208(const ScriptArguments& args, const ScriptFloat min, const Scrip @arg result */ void opcode_0209(const ScriptArguments& args, const ScriptInt min, const ScriptInt max, ScriptInt& result) { - result = args.getVM()->getRandomNumber(min, max); + result = args.getWorld()->getRandomNumber(min, max); } /** @@ -7745,7 +7745,8 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip // Return the handle for any random character in this zone and use lifetime for use by script // @todo verify if the lifetime is actually changed in the original game // husho: lifetime is changed to mission object lifetime - unsigned int randomIndex = std::rand() % candidateCount; + auto randomIndex = + args.getWorld()->getRandomNumber(0u, candidateCount); const auto [candidateId, candidatePtr] = candidates.at(randomIndex); auto character = static_cast(candidatePtr); character->setLifetime(GameObject::MissionLifetime); @@ -9952,8 +9953,8 @@ void opcode_0376(const ScriptArguments& args, ScriptVec3 coord, const int groupId = zone ? (day ? zone->pedGroupDay : zone->pedGroupNight) : 0; const auto& pedGroup = data->pedgroups.at(groupId); - const auto model = pedGroup.at(args.getVM()->getRandomNumber( - static_cast(0), pedGroup.size() - 1)); + const auto model = + pedGroup.at(args.getWorld()->getRandomNumber(0u, pedGroup.size() - 1)); character = world->createPedestrian(model, coord); character->applyOffset(); }