mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Add some knobs to our RNG class
Also included is an additive lagged fibonacci generator that should is very similar to EQ's. Also added BIASED_INT_DIST in case someone wants to use "bad" int distribution to more closely match EQ as well. An option to set a custom engine (just in case people would like to play with other std engines) is available. There is also support for GCC's SIMD accelerated extension to std random engines. All these options are hidden behind advanced options in CMake since they're rather advanced knobs.
This commit is contained in:
parent
8a2a1b152e
commit
ddb14187b0
@ -131,6 +131,47 @@ OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
|
|||||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
|
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
|
||||||
OPTION(EQEMU_PREFER_LUA "Build with normal Lua even if LuaJIT is found." OFF)
|
OPTION(EQEMU_PREFER_LUA "Build with normal Lua even if LuaJIT is found." OFF)
|
||||||
|
|
||||||
|
#PRNG options
|
||||||
|
OPTION(EQEMU_ADDITIVE_LFIB_PRNG "Use Additive LFib for PRNG." OFF)
|
||||||
|
MARK_AS_ADVANCED(EQEMU_ADDITIVE_LFIB_PRNG)
|
||||||
|
OPTION(EQEMU_BIASED_INT_DIST "Use biased int dist instead of uniform." OFF)
|
||||||
|
MARK_AS_ADVANCED(EQEMU_BIASED_INT_DIST)
|
||||||
|
SET(EQEMU_CUSTOM_PRNG_ENGINE "" CACHE STRING "Custom random engine. (ex. std::default_random_engine)")
|
||||||
|
MARK_AS_ADVANCED(EQEMU_CUSTOM_PRNG_ENGINE)
|
||||||
|
|
||||||
|
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
OPTION(EQEMU_SFMT19937 "Use GCC's extention for SIMD Fast MT19937." OFF)
|
||||||
|
MARK_AS_ADVANCED(EQEMU_SFMT19937)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(EQEMU_ADDITIVE_LFIB_PRNG)
|
||||||
|
ADD_DEFINITIONS(-DUSE_ADDITIVE_LFIB_PRNG)
|
||||||
|
IF(EQEMU_SFMT19937)
|
||||||
|
MESSAGE(STATUS "SFMT19937 and ADDITITVE_LFIB_PRNG both set, SFMT19937 ignored.")
|
||||||
|
SET(EQEMU_SFMT19937 OFF)
|
||||||
|
ENDIF()
|
||||||
|
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||||
|
MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and ADDITITVE_LFIB_PRNG both set, CUSTOM_PRNG_ENGINE ignored.")
|
||||||
|
SET(EQEMU_CUSTOM_PRNG_ENGINE "")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(EQEMU_SFMT19937)
|
||||||
|
ADD_DEFINITIONS(-DUSE_SFMT19937)
|
||||||
|
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||||
|
MESSAGE(STATUS "CUSTOM_PRNG_ENGINE and SFMT19937 both set, CUSTOM_PRNG_ENGINE ignored.")
|
||||||
|
SET(EQEMU_CUSTOM_PRNG_ENGINE "")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(NOT EQEMU_CUSTOM_PRNG_ENGINE STREQUAL "")
|
||||||
|
ADD_DEFINITIONS(-DUSE_CUSTOM_PRNG_ENGINE=${EQEMU_CUSTOM_PRNG_ENGINE})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(EQEMU_BIASED_INT_DIST)
|
||||||
|
ADD_DEFINITIONS(-DBIASED_INT_DIST)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
IF(EQEMU_COMMANDS_LOGGING)
|
IF(EQEMU_COMMANDS_LOGGING)
|
||||||
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
|
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
|
||||||
ENDIF(EQEMU_COMMANDS_LOGGING)
|
ENDIF(EQEMU_COMMANDS_LOGGING)
|
||||||
|
|||||||
@ -451,6 +451,7 @@ SET(repositories
|
|||||||
)
|
)
|
||||||
|
|
||||||
SET(common_headers
|
SET(common_headers
|
||||||
|
additive_lagged_fibonacci_engine.h
|
||||||
any.h
|
any.h
|
||||||
base_packet.h
|
base_packet.h
|
||||||
base_data.h
|
base_data.h
|
||||||
|
|||||||
147
common/additive_lagged_fibonacci_engine.h
Normal file
147
common/additive_lagged_fibonacci_engine.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/* EQEMu: Everquest Server Emulator
|
||||||
|
Copyright (C) 2001-2021 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
|
This program 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 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
are required to give you total support for your newly bought product;
|
||||||
|
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 this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an additive lagged fibonacci generator as seen in The Art of Computer Programming, Vol. 2
|
||||||
|
* This should roughly match the implementation that EQ's client uses and be compatible with our Random class
|
||||||
|
*
|
||||||
|
* EQ's rand looks like it was from an example implementation that as posted on pscode.com
|
||||||
|
*
|
||||||
|
* You might also want to consider defining BIASED_INT_DIST as well to more closely match EQ
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EQ {
|
||||||
|
template<typename UIntType, size_t w, size_t j, size_t k>
|
||||||
|
class additive_lagged_fibonacci_engine {
|
||||||
|
static_assert(std::is_unsigned<UIntType>::value, "result_type must be an unsigned integral type");
|
||||||
|
static_assert(0u < j && j < k, "0 < j < k");
|
||||||
|
static_assert(0u < w && w <= std::numeric_limits<UIntType>::digits,
|
||||||
|
"template argument substituting w out of bounds");
|
||||||
|
|
||||||
|
public:
|
||||||
|
using result_type = UIntType;
|
||||||
|
static constexpr size_t word_size = w;
|
||||||
|
static constexpr size_t short_lag = j;
|
||||||
|
static constexpr size_t long_lag = k;
|
||||||
|
static constexpr result_type default_seed = 19780503u; // default for subtract_with_carry_engine
|
||||||
|
|
||||||
|
additive_lagged_fibonacci_engine() : additive_lagged_fibonacci_engine(default_seed) {}
|
||||||
|
|
||||||
|
explicit additive_lagged_fibonacci_engine(result_type sd) { seed(sd); }
|
||||||
|
|
||||||
|
void seed(result_type seed = default_seed)
|
||||||
|
{
|
||||||
|
state1 = long_lag - long_lag;
|
||||||
|
state2 = long_lag - short_lag;
|
||||||
|
state[0] = static_cast<int>(seed) & ((1u << word_size) - 1);
|
||||||
|
state[1] = 1;
|
||||||
|
for (int i = 2; i < long_lag; ++i)
|
||||||
|
state[i] = (state[i - 1] + state[i - 2]) & ((1u << word_size) - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: seed via seed_seq
|
||||||
|
|
||||||
|
static constexpr result_type min() { return 0; }
|
||||||
|
static constexpr result_type max() { return ((1u << word_size) - 1) >> 6; }
|
||||||
|
|
||||||
|
void discard(unsigned long long z) {
|
||||||
|
for (; z != 0ULL; --z)
|
||||||
|
(*this)();
|
||||||
|
}
|
||||||
|
|
||||||
|
result_type operator()() {
|
||||||
|
result_type rand = (state[state1] + state[state2]) & ((1u << word_size) - 1);
|
||||||
|
state[state1] = rand;
|
||||||
|
if (++state1 == long_lag)
|
||||||
|
state1 = 0;
|
||||||
|
if (++state2 == long_lag)
|
||||||
|
state2 = 0;
|
||||||
|
|
||||||
|
return rand >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
result_type state1;
|
||||||
|
result_type state2;
|
||||||
|
result_type state[long_lag];
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename UInt, size_t W, size_t J, size_t K>
|
||||||
|
friend bool operator==(const additive_lagged_fibonacci_engine<UInt, W, J, K> &x,
|
||||||
|
const additive_lagged_fibonacci_engine<UInt, W, J, K> &y)
|
||||||
|
{
|
||||||
|
return std::equal(x.state, x.state + long_lag, y.state) && x.state1 == y.state1 &&
|
||||||
|
x.state2 == y.state2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename UInt, size_t W, size_t J, size_t K>
|
||||||
|
friend bool operator!=(const additive_lagged_fibonacci_engine<UInt, W, J, K> &x,
|
||||||
|
const additive_lagged_fibonacci_engine<UInt, W, J, K> &y)
|
||||||
|
{ return !(x == y); }
|
||||||
|
|
||||||
|
template<typename UInt, size_t W, size_t J, size_t K, typename CharT, typename Traits>
|
||||||
|
friend std::basic_ostream<CharT, Traits> &
|
||||||
|
operator<<(std::basic_istream<CharT, Traits> &os, additive_lagged_fibonacci_engine<UInt, W, J, K> &x)
|
||||||
|
{
|
||||||
|
using ios_base = typename std::basic_istream<CharT, Traits>::ios_base;
|
||||||
|
|
||||||
|
const typename ios_base::fmtflags flags = os.flags();
|
||||||
|
const CharT fill = os.fill();
|
||||||
|
const CharT space = os.widen(' ');
|
||||||
|
os.flags(ios_base::dec | ios_base::fixed | ios_base::left);
|
||||||
|
os.fill(space);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < long_lag; ++i)
|
||||||
|
os << x.state[i] << space;
|
||||||
|
os << x.state1 << space << x.state2;
|
||||||
|
|
||||||
|
os.flags(flags);
|
||||||
|
os.fill(fill);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename UInt, size_t W, size_t J, size_t K, typename CharT, typename Traits>
|
||||||
|
friend std::basic_istream<CharT, Traits> &
|
||||||
|
operator>>(std::basic_istream<CharT, Traits> &is, additive_lagged_fibonacci_engine<UInt, W, J, K> &x)
|
||||||
|
{
|
||||||
|
using ios_base = typename std::basic_istream<CharT, Traits>::ios_base;
|
||||||
|
|
||||||
|
const typename ios_base::fmtflags flags = is.flags();
|
||||||
|
is.flags(ios_base::dec | ios_base::skipws);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < long_lag; ++i)
|
||||||
|
is >> x.state[i];
|
||||||
|
is >> x.state1;
|
||||||
|
is >> x.state2;
|
||||||
|
|
||||||
|
is.flags(flags);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using EQRand = additive_lagged_fibonacci_engine<uint32_t, 30, 24, 55>;
|
||||||
|
};
|
||||||
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
/* EQEMu: Everquest Server Emulator
|
||||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
Copyright (C) 2001-2021 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -25,10 +25,24 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
/* This uses mt19937 seeded with the std::random_device
|
#ifdef USE_SFMT19937
|
||||||
* The idea is to have this be included as a member of another class
|
// only GCC supports, so lets turn it off
|
||||||
* so mocking out for testing is easier
|
#ifndef __GNUC__
|
||||||
* If you need to reseed random.Reseed()
|
#undef USE_SFMT19937
|
||||||
|
#endif
|
||||||
|
#ifdef __clang__
|
||||||
|
#undef USE_SFMT19937
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ADDITIVE_LFIB_PRNG
|
||||||
|
#include "additive_lagged_fibonacci_engine.h"
|
||||||
|
#elif defined(USE_SFMT19937)
|
||||||
|
#include <ext/random>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This uses mt19937 (or other compatible engine) seeded with the std::random_device. The idea is to have this be
|
||||||
|
* included as a member of another class so mocking out for testing is easier If you need to reseed random.Reseed()
|
||||||
* Eventually this should be derived from an abstract base class
|
* Eventually this should be derived from an abstract base class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -40,7 +54,12 @@ namespace EQ {
|
|||||||
{
|
{
|
||||||
if (low > high)
|
if (low > high)
|
||||||
std::swap(low, high);
|
std::swap(low, high);
|
||||||
|
// EQ uses biased int distribution, so I guess we can support it :P
|
||||||
|
#ifdef BIASED_INT_DIST
|
||||||
|
return low + m_gen() % (high - low + 1);
|
||||||
|
#else
|
||||||
return int_dist(m_gen, int_param_t(low, high)); // [low, high]
|
return int_dist(m_gen, int_param_t(low, high)); // [low, high]
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// AKA old MakeRandomFloat
|
// AKA old MakeRandomFloat
|
||||||
@ -98,11 +117,24 @@ namespace EQ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifndef BIASED_INT_DIST
|
||||||
typedef std::uniform_int_distribution<int>::param_type int_param_t;
|
typedef std::uniform_int_distribution<int>::param_type int_param_t;
|
||||||
typedef std::uniform_real_distribution<double>::param_type real_param_t;
|
|
||||||
std::mt19937 m_gen;
|
|
||||||
std::uniform_int_distribution<int> int_dist;
|
std::uniform_int_distribution<int> int_dist;
|
||||||
|
#endif
|
||||||
|
typedef std::uniform_real_distribution<double>::param_type real_param_t;
|
||||||
std::uniform_real_distribution<double> real_dist;
|
std::uniform_real_distribution<double> real_dist;
|
||||||
|
// define USE_CUSTOM_PRNG_ENGINE to any supported random engine like:
|
||||||
|
// #define USE_CUSTOM_PRNG_ENGINE std::default_random_engine
|
||||||
|
#ifdef USE_ADDITIVE_LFIB_PRNG
|
||||||
|
EQRand
|
||||||
|
#elif defined(USE_SFMT19937)
|
||||||
|
__gnu_cxx::sfmt19937
|
||||||
|
#elif defined(USE_CUSTOM_PRNG_ENGINE)
|
||||||
|
USE_CUSTOM_PRNG_ENGINE
|
||||||
|
#else
|
||||||
|
std::mt19937
|
||||||
|
#endif
|
||||||
|
m_gen;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user