mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 14:27:16 +00:00
(svn r2583) Move OS specific code out of misc.c
Added support for Mersenne Twister random number generator (not implemented in network yet) Wrap player randoms around #ifdef
This commit is contained in:
parent
c964809d37
commit
71f9078bdd
27
functions.h
27
functions.h
@ -93,6 +93,21 @@ void NORETURN CDECL error(const char *str, ...);
|
||||
|
||||
//#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 *str, ...);
|
||||
#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);
|
||||
|
72
mersenne.c
Normal file
72
mersenne.c
Normal file
@ -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
|
63
misc.c
63
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 <devices/timer.h>
|
||||
# include <dos/dos.h>
|
||||
|
||||
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);
|
||||
|
@ -773,7 +773,9 @@ static void NetworkInitialize(void)
|
||||
|
||||
_network_reconnect = 0;
|
||||
|
||||
#ifdef PLAYER_SEED_RANDOM
|
||||
InitPlayerRandoms();
|
||||
#endif
|
||||
|
||||
NetworkUDPInitialize();
|
||||
}
|
||||
|
@ -488,11 +488,13 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
|
||||
// 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);
|
||||
|
||||
|
@ -323,7 +323,9 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
|
||||
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_MAP)
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
47
unix.c
47
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 <devices/timer.h>
|
||||
# include <dos/dos.h>
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -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;
|
||||
|
7
win32.c
7
win32.c
@ -2124,6 +2124,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
_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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user