diff --git a/functions.h b/functions.h --- a/functions.h +++ b/functions.h @@ -93,6 +93,21 @@ void NORETURN CDECL error(const char *st //#define RANDOM_DEBUG + +// Enable this to produce higher quality random numbers. +// Doesn't work with network yet. +//#define MERSENNE_TWISTER + +// Mersenne twister functions +void SeedMT(uint32 seed); +uint32 RandomMT(void); + + +#ifdef MERSENNE_TWISTER + static inline uint32 Random(void) { return RandomMT(); } + uint RandomRange(uint max); +#else + #ifdef RANDOM_DEBUG #define Random() DoRandom(__LINE__, __FILE__) uint32 DoRandom(int line, const char *file); @@ -101,12 +116,18 @@ void NORETURN CDECL error(const char *st #else uint32 Random(void); uint RandomRange(uint max); +#endif +#endif // MERSENNE_TWISTER - static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); } - static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); } +static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); } +static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); } + + +#ifdef PLAYER_SEED_RANDOM +void InitPlayerRandoms(void); #endif -void InitPlayerRandoms(void); + uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */ uint InteractiveRandomRange(uint max); diff --git a/mersenne.c b/mersenne.c new file mode 100644 --- /dev/null +++ b/mersenne.c @@ -0,0 +1,72 @@ +#include "stdafx.h" +#include "openttd.h" + +#ifdef MERSENNE_TWISTER + +// Source code for Mersenne Twister. +// A Random number generator with much higher quality random numbers. + +#define N (624) // length of _mt_state vector +#define M (397) // a period parameter +#define K (0x9908B0DFU) // a magic constant +#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u +#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u +#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u +#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v + +static uint32 _mt_state[N+1]; // _mt_state vector + 1 extra to not violate ANSI C +static uint32 *_mt_next; // _mt_next random value is computed from here +static int _mt_left = -1; // can *_mt_next++ this many times before reloading + +void SeedMT(uint32 seed) +{ + register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state; + register int j; + + for(_mt_left=0, *s++=x, j=N; --j; + *s++ = (x*=69069U) & 0xFFFFFFFFU); + } + + +static uint32 ReloadMT(void) + { + register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1; + register int j; + + if(_mt_left < -1) + SeedMT(4357U); + + _mt_left=N-1, _mt_next=_mt_state+1; + + for(s0=_mt_state[0], s1=_mt_state[1], j=N-M+1; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + for(pM=_mt_state, j=M; --j; s0=s1, s1=*p2++) + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + + s1=_mt_state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9D2C5680U; + s1 ^= (s1 << 15) & 0xEFC60000U; + return(s1 ^ (s1 >> 18)); + } + + +uint32 RandomMT(void) +{ + uint32 y; + + if(--_mt_left < 0) + return ReloadMT(); + + y = *_mt_next++; + y ^= (y >> 11); + y ^= (y << 7) & 0x9D2C5680U; + y ^= (y << 15) & 0xEFC60000U; + return y ^ (y >> 18); +} +#else + +void SeedMT(uint32 seed) {} + +#endif \ No newline at end of file diff --git a/misc.c b/misc.c --- a/misc.c +++ b/misc.c @@ -29,13 +29,14 @@ static inline uint32 ROR(uint32 x, int n it completely! -- TrueLight */ #undef PLAYER_SEED_RANDOM +#ifndef MERSENNE_TWISTER + #ifdef RANDOM_DEBUG #include "network_data.h" - uint32 DoRandom(int line, const char *file) -#else +#else // RANDOM_DEBUG uint32 Random(void) -#endif +#endif // RANDOM_DEBUG { uint32 s; @@ -66,8 +67,9 @@ uint32 t; return _random_seeds[0][1] = ROR(s, 3) - 1; #endif } +#endif // MERSENNE_TWISTER -#ifdef RANDOM_DEBUG +#if defined(RANDOM_DEBUG) && !defined(MERSENNE_TWISTER) uint DoRandomRange(uint max, int line, const char *file) { return (uint16)DoRandom(line, file) * max >> 16; @@ -79,6 +81,7 @@ uint RandomRange(uint max) } #endif + uint32 InteractiveRandom(void) { uint32 t = _random_seeds[1][1]; @@ -92,6 +95,8 @@ uint InteractiveRandomRange(uint max) return (uint16)InteractiveRandom() * max >> 16; } + +#ifdef PLAYER_SEED_RANDOM void InitPlayerRandoms(void) { int i; @@ -100,6 +105,7 @@ void InitPlayerRandoms(void) _player_seeds[i][1]=InteractiveRandom(); } } +#endif void SetDate(uint date) { @@ -112,55 +118,6 @@ void SetDate(uint date) #endif /* ENABLE_NETWORK */ } - -#ifdef ENABLE_NETWORK - -// multi os compatible sleep function - -#ifdef __AMIGA__ -// usleep() implementation -# include -# include - - extern struct Device *TimerBase = NULL; - extern struct MsgPort *TimerPort = NULL; - extern struct timerequest *TimerRequest = NULL; -#endif // __AMIGA__ - -void CSleep(int milliseconds) -{ - #if defined(WIN32) - Sleep(milliseconds); - #endif - #if defined(UNIX) - #if !defined(__BEOS__) && !defined(__AMIGA__) - usleep(milliseconds * 1000); - #endif - #ifdef __BEOS__ - snooze(milliseconds * 1000); - #endif - #if defined(__AMIGA__) - { - ULONG signals; - ULONG TimerSigBit = 1 << TimerPort->mp_SigBit; - - // send IORequest - TimerRequest->tr_node.io_Command = TR_ADDREQUEST; - TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000; - TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000; - SendIO((struct IORequest *)TimerRequest); - - if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) { - AbortIO((struct IORequest *)TimerRequest); - } - WaitIO((struct IORequest *)TimerRequest); - } - #endif // __AMIGA__ - #endif -} - -#endif /* ENABLE_NETWORK */ - void InitializeVehicles(void); void InitializeWaypoints(void); void InitializeDepot(void); diff --git a/network.c b/network.c --- a/network.c +++ b/network.c @@ -773,7 +773,9 @@ static void NetworkInitialize(void) _network_reconnect = 0; +#ifdef PLAYER_SEED_RANDOM InitPlayerRandoms(); +#endif NetworkUDPInitialize(); } diff --git a/network_client.c b/network_client.c --- a/network_client.c +++ b/network_client.c @@ -488,11 +488,13 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER // Check if this was the last packet if (maptype == MAP_PACKET_END) { // We also get, very nice, the player_seeds in this packet +#ifdef PLAYER_SEED_RANDOM int i; for (i = 0; i < MAX_PLAYERS; i++) { _player_seeds[i][0] = NetworkRecv_uint32(MY_CLIENT, p); _player_seeds[i][1] = NetworkRecv_uint32(MY_CLIENT, p); } +#endif fclose(file_pointer); diff --git a/network_server.c b/network_server.c --- a/network_server.c +++ b/network_server.c @@ -323,7 +323,9 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA NetworkSend_Packet(p, cs); if (feof(file_pointer)) { // Done reading! +#ifdef PLAYER_SEED_RANDOM int i; +#endif Packet *p; // XXX - Delete this when patch-settings are saved in-game @@ -331,11 +333,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA p = NetworkSend_Init(PACKET_SERVER_MAP); NetworkSend_uint8(p, MAP_PACKET_END); +#ifdef PLAYER_SEED_RANDOM // Send the player_seeds in this packet for (i = 0; i < MAX_PLAYERS; i++) { NetworkSend_uint32(p, _player_seeds[i][0]); NetworkSend_uint32(p, _player_seeds[i][1]); } +#endif NetworkSend_Packet(p, cs); // Set the status to DONE_MAP, no we will wait for the client diff --git a/openttd.c b/openttd.c --- a/openttd.c +++ b/openttd.c @@ -676,7 +676,9 @@ int ttd_main(int argc, char* argv[]) InitializeGUI(); IConsoleCmdExec("exec scripts/autoexec.scr 0"); +#ifdef PLAYER_SEED_RANDOM InitPlayerRandoms(); +#endif GenerateWorld(1, 64, 64); // Make the viewport initialization happy diff --git a/unix.c b/unix.c --- a/unix.c +++ b/unix.c @@ -474,6 +474,7 @@ int CDECL main(int argc, char* argv[]) #endif _random_seeds[0][1] = _random_seeds[0][0] = time(NULL); + SeedMT(_random_seeds[0][1]); signal(SIGPIPE, SIG_IGN); @@ -581,3 +582,49 @@ void JoinOTTDThread(void) pthread_join(thread1, NULL); } + + + +#ifdef ENABLE_NETWORK + +// multi os compatible sleep function + +#ifdef __AMIGA__ +// usleep() implementation +# include +# include + + extern struct Device *TimerBase = NULL; + extern struct MsgPort *TimerPort = NULL; + extern struct timerequest *TimerRequest = NULL; +#endif // __AMIGA__ + +void CSleep(int milliseconds) +{ + #if !defined(__BEOS__) && !defined(__AMIGA__) + usleep(milliseconds * 1000); + #endif + #ifdef __BEOS__ + snooze(milliseconds * 1000); + #endif + #if defined(__AMIGA__) + { + ULONG signals; + ULONG TimerSigBit = 1 << TimerPort->mp_SigBit; + + // send IORequest + TimerRequest->tr_node.io_Command = TR_ADDREQUEST; + TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000; + TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000; + SendIO((struct IORequest *)TimerRequest); + + if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) { + AbortIO((struct IORequest *)TimerRequest); + } + WaitIO((struct IORequest *)TimerRequest); + } + #endif // __AMIGA__ +} + +#endif /* ENABLE_NETWORK */ + diff --git a/variables.h b/variables.h --- a/variables.h +++ b/variables.h @@ -82,7 +82,10 @@ VARDEF uint16 _disaster_delay; VARDEF uint16 _station_tick_ctr; VARDEF uint32 _random_seeds[2][2]; + +#ifdef PLAYER_SEED_RANDOM VARDEF uint32 _player_seeds[MAX_PLAYERS][2]; +#endif // Iterator through all towns in OnTick_Town VARDEF uint32 _cur_town_ctr; diff --git a/win32.c b/win32.c --- a/win32.c +++ b/win32.c @@ -2124,6 +2124,7 @@ int APIENTRY WinMain(HINSTANCE hInstance _random_seeds[0][0] = GetTickCount(); _random_seeds[0][1] = _random_seeds[0][0] * 0x1234567; #endif + SeedMT(_random_seeds[0][0]); argc = ParseCommandLine(GetCommandLine(), argv, lengthof(argv)); @@ -2263,3 +2264,9 @@ void JoinOTTDThread(void) WaitForSingleObject(hThread, INFINITE); } + + +void CSleep(int milliseconds) +{ + Sleep(milliseconds); +} \ No newline at end of file