logo logo

 Back to main page

The NWNX Community Forum

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
 
Replacing rand()

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Linux development
View previous topic :: View next topic  
Author Message
lperkins2



Joined: 23 Apr 2016
Posts: 1

PostPosted: Mon Apr 25, 2016 23:26    Post subject: Replacing rand() Reply with quote

There have been a few efforts in the past to provide better pseudo-random number generation for scripts in nwnx; but, this requires changing and recompiling scripts to take advantage of the new random function. Also, new random functions can't replace the random numbers used in attack rolls and other core-engine functions. I decided to try to provide a replacement PRNG that does override the core dice rolling functionality.

Turns out (on the linux build at least), it's just making a call to the system prng rand (or std::rand in C++). This can easily be verified by declaring an LD_PRELOAD with
`int rand() {return 42;}` which will make all D20s come up `3`. After that, it's a simple matter of creating a rand function which, on its first invocation, will initialize a mersenne twister prng from the system time and using it to feed random numbers.

To avoid modulo bias, the highest number returned from rand() should be (n*dsize)-1, since rand needs to work perfectly for all standard dice sizes, I'm using 191999 (8*12*20*100 - 1), which satisfies n*d-1 for all D&D values of d. The extra factor of 20 wouldn't be necessary, but rand() should be capable of returning numbers higher than 32767.

Code:

// Licens: LGPL2
#include <random>
#include <cstdio>
#include <cstdlib>
#include <chrono>



std::mt19937 my_generator;
std::uniform_int_distribution<int> my_distribution(0,191999);

int initted=0;

typedef std::chrono::high_resolution_clock myclock;


int rand(){
    if (!initted){
        initted=1;
       

        myclock::time_point my_time = myclock::now();
       
        auto seed = my_time.time_since_epoch().count();
        my_generator.seed(seed);
        printf("Using mt19937 mersenne_twister_engine with seed: %Li\n", seed);
    }
   

    int my_rn = my_distribution(my_generator);
   
   
    if (getenv( "DEBUG\0" )){

        printf("my rn: %i\n", my_rn);
    }
   
    return my_rn;
}




Compiled with gcc-4.8.5 on gentoo

Code:

g++ -fPIC -m32 -mcpu=i386 -o rand.so rand.cpp --shared -std=c++11



If there's interest, I can provide a binary build, but if you're running it on linux you can probably just compile it, right Smile

To use it, simply add it to the LD_PRELOAD in the startup script,

Code:

LD_PRELOAD=./rand.so:./nwnx2.so



Or for the SP client
Code:

LD_PRELOAD=./rand.so:./nwmovies.so
Back to top
View user's profile Send private message
leo_x



Joined: 25 Aug 2010
Posts: 75

PostPosted: Thu May 19, 2016 0:50    Post subject: Reply with quote

Cool stuff!
_________________
the awakening (PW Action)
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Linux development All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group