diff --git a/Core/GameEngine/Source/Common/RandomValue.cpp b/Core/GameEngine/Source/Common/RandomValue.cpp index e5a871d65f..e4e67b14e6 100644 --- a/Core/GameEngine/Source/Common/RandomValue.cpp +++ b/Core/GameEngine/Source/Common/RandomValue.cpp @@ -28,52 +28,50 @@ #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - #include "Lib/BaseType.h" #include "Common/RandomValue.h" #include "Common/crc.h" #include "Common/Debug.h" #include "GameLogic/GameLogic.h" -//#define DETERMINISTIC // to allow repetition for debugging - - #undef DEBUG_RANDOM_CLIENT -#undef DEBUG_RANDOM_LOGIC #undef DEBUG_RANDOM_AUDIO +#undef DEBUG_RANDOM_LOGIC //#define DEBUG_RANDOM_CLIENT -//#define DEBUG_RANDOM_LOGIC //#define DEBUG_RANDOM_AUDIO +//#define DEBUG_RANDOM_LOGIC +//#define DETERMINISTIC // to allow repetition for debugging -static const Real theMultFactor = 1.0f / (powf(2, 8 * sizeof(UnsignedInt)) - 1.0f); +static const Real theMultFactor = 1.0f / static_cast(UINT_MAX); // Initial seed values. static UnsignedInt theGameClientSeed[6] = { - 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L + 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L }; static UnsignedInt theGameAudioSeed[6] = { - 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L + 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L }; -static UnsignedInt theGameLogicBaseSeed = 0; static UnsignedInt theGameLogicSeed[6] = { - 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L + 0xf22d0e56L, 0x883126e9L, 0xc624dd2fL, 0x702c49cL, 0x9e353f7dL, 0x6fdf3b64L }; -// Add with carry. SUM is replaced with A + B + C, C is replaced with 1 if there was a carry, 0 if there wasn't. A carry occurred if the sum is less than one of the inputs. This is addition, so carry can never be more than one. -#define ADC(SUM, A, B, C) SUM = (A) + (B) + (C); C = ((SUM < (A)) || (SUM < (B))) +static UnsignedInt theGameLogicBaseSeed = 0; + +// Add with carry. SUM is replaced with A + B + C, C is replaced with 1 if there was a carry, 0 if there wasn't. +// A carry occurred if the sum is less than one of the inputs. This is addition, so carry can never be more than one. +#define ADC(SUM, A, B, C) SUM = (A) + (B) + (C); C = ((SUM < (A)) || (SUM < (B))) -static UnsignedInt randomValue(UnsignedInt *seed) +static UnsignedInt randomValue(UnsignedInt (&seed)[6]) { UnsignedInt ax; UnsignedInt c = 0; - ADC(ax, seed[5], seed[4], c); /* mov ax,seed+20 */ /* add ax,seed+16 */ seed[4] = ax; /* mov seed+8,ax */ @@ -108,10 +106,11 @@ static UnsignedInt randomValue(UnsignedInt *seed) } } } - return(ax); + + return ax; } -static void seedRandom(UnsignedInt SEED, UnsignedInt *seed) +static void seedRandom(UnsignedInt SEED, UnsignedInt (&seed)[6]) { UnsignedInt ax; @@ -130,24 +129,6 @@ static void seedRandom(UnsignedInt SEED, UnsignedInt *seed) seed[5] = ax; /* mov seed+20,eax */ } -// -// It is necessary to separate the GameClient and GameLogic usage of random -// values to ensure that the GameLogic remains deterministic, regardless -// of the effects displayed on the GameClient. -// - -UnsignedInt GetGameLogicRandomSeed() -{ - return theGameLogicBaseSeed; -} - -UnsignedInt GetGameLogicRandomSeedCRC() -{ - CRC c; - c.computeCRC(theGameLogicSeed, 6*sizeof(UnsignedInt)); - return c.get(); -} - void InitRandom() { #ifdef DETERMINISTIC @@ -157,10 +138,10 @@ void InitRandom() seedRandom(0, theGameLogicSeed); theGameLogicBaseSeed = 0; #else - time_t seconds = time( nullptr ); + const time_t seconds = time( nullptr ); - seedRandom(seconds, theGameAudioSeed); seedRandom(seconds, theGameClientSeed); + seedRandom(seconds, theGameAudioSeed); seedRandom(seconds, theGameLogicSeed); theGameLogicBaseSeed = seconds; #endif @@ -168,125 +149,142 @@ void InitRandom() void InitRandom( UnsignedInt seed ) { - seedRandom(seed, theGameAudioSeed); +#ifdef DETERMINISTIC + seed = 0; +#endif + seedRandom(seed, theGameClientSeed); + seedRandom(seed, theGameAudioSeed); seedRandom(seed, theGameLogicSeed); theGameLogicBaseSeed = seed; + #ifdef DEBUG_RANDOM_LOGIC -DEBUG_LOG(( "InitRandom %08lx",seed)); + DEBUG_LOG(("InitRandom %08lx", seed)); #endif } // -// Integer random value +// It is necessary to separate the GameClient and GameLogic usage of random +// values to ensure that the GameLogic remains deterministic, regardless +// of the effects displayed on the GameClient. // -Int GetGameLogicRandomValue( int lo, int hi, const char *file, int line ) -{ - //Int delta = hi - lo + 1; - //Int rval; - - //if (delta == 0) - //return hi; - //rval = ((Int)(randomValue(theGameLogicSeed) % delta)) + lo; +UnsignedInt GetGameLogicRandomSeed() +{ + return theGameLogicBaseSeed; +} - UnsignedInt delta = hi - lo + 1; - //UnsignedInt temp; - Int rval; +UnsignedInt GetGameLogicRandomSeedCRC() +{ + CRC c; + c.computeCRC(theGameLogicSeed, sizeof(theGameLogicSeed)); + return c.get(); +} - if (delta == 0) +// +// Integer random value +// +Int GetGameClientRandomValue( int lo, int hi, const char *file, int line ) +{ + if (lo >= hi) return hi; - rval = ((Int)(randomValue(theGameLogicSeed) % delta)) + lo; - //temp = randomValue(theGameLogicSeed); - //temp = temp % delta; - - //rval = temp + lo; + const UnsignedInt delta = hi - lo + 1; + const Int rval = ((Int)(randomValue(theGameClientSeed) % delta)) + lo; -/**/ -#ifdef DEBUG_RANDOM_LOGIC -DEBUG_LOG(( "%d: GetGameLogicRandomValue = %d (%d - %d), %s line %d", - TheGameLogic->getFrame(), rval, lo, hi, file, line )); +#ifdef DEBUG_RANDOM_CLIENT + DEBUG_LOG(( "%d: GetGameClientRandomValue = %d (%d - %d), %s line %d", + TheGameLogic ? TheGameLogic->getFrame() : -1, rval, lo, hi, file, line )); #endif -/**/ + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } // -// TheSuperHackers @info This function does not change the seed values with retail compatibility disabled. -// Consecutive calls always return the same value for the same combination of min / max values, assuming the seed values haven't changed in between. -// The intended use case for this function are randomized values that are desirable to be synchronized across clients, -// but should not result in a mismatch if they aren't synchronized; e.g. for scripted audio events. +// Real valued random value // -Int GetGameLogicRandomValueUnchanged( int lo, int hi, const char *file, int line ) +Real GetGameClientRandomValueReal( Real lo, Real hi, const char *file, int line ) { -#if RETAIL_COMPATIBLE_CRC - return GetGameLogicRandomValue(lo, hi, file, line); -#endif - - const UnsignedInt delta = hi - lo + 1; - if (delta == 0) + if (lo >= hi) return hi; - UnsignedInt seed[ARRAY_SIZE(theGameLogicSeed)]; - memcpy(&seed[0], &theGameLogicSeed[0], sizeof(seed)); + const Real delta = hi - lo; + const Real rval = ((Real)(randomValue(theGameClientSeed)) * theMultFactor) * delta + lo; - const Int rval = ((Int)(randomValue(seed) % delta)) + lo; +#ifdef DEBUG_RANDOM_CLIENT + DEBUG_LOG(( "%d: GetGameClientRandomValueReal = %f, %s line %d", + TheGameLogic->getFrame(), rval, file, line )); +#endif DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); + return rval; +} -#ifdef DEBUG_RANDOM_LOGIC - DEBUG_LOG(( "%d: GetGameLogicRandomValueUnchanged = %d (%d - %d), %s line %d", +// +// Integer random value +// +Int GetGameAudioRandomValue( int lo, int hi, const char *file, int line ) +{ + if (lo >= hi) + return hi; + + const UnsignedInt delta = hi - lo + 1; + const Int rval = ((Int)(randomValue(theGameAudioSeed) % delta)) + lo; + +#ifdef DEBUG_RANDOM_AUDIO + DEBUG_LOG(( "%d: GetGameAudioRandomValue = %d (%d - %d), %s line %d", TheGameLogic->getFrame(), rval, lo, hi, file, line )); #endif + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } // -// Integer random value +// Real valued random value // -Int GetGameClientRandomValue( int lo, int hi, const char *file, int line ) +Real GetGameAudioRandomValueReal( Real lo, Real hi, const char *file, int line ) { - UnsignedInt delta = hi - lo + 1; - Int rval; - - if (delta == 0) + if (lo >= hi) return hi; - rval = ((Int)(randomValue(theGameClientSeed) % delta)) + lo; + const Real delta = hi - lo; + const Real rval = ((Real)(randomValue(theGameAudioSeed)) * theMultFactor) * delta + lo; -/**/ -#ifdef DEBUG_RANDOM_CLIENT -DEBUG_LOG(( "%d: GetGameClientRandomValue = %d (%d - %d), %s line %d", - TheGameLogic ? TheGameLogic->getFrame() : -1, rval, lo, hi, file, line )); +#ifdef DEBUG_RANDOM_AUDIO + DEBUG_LOG(( "%d: GetGameAudioRandomValueReal = %f, %s line %d", + TheGameLogic->getFrame(), rval, file, line )); #endif -/**/ + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } // // Integer random value // -Int GetGameAudioRandomValue( int lo, int hi, const char *file, int line ) +Int GetGameLogicRandomValue( int lo, int hi, const char *file, int line ) { - UnsignedInt delta = hi - lo + 1; - Int rval; - +#if RETAIL_COMPATIBLE_CRC + const UnsignedInt delta = hi - lo + 1; if (delta == 0) return hi; +#else + if (lo >= hi) + return hi; - rval = ((Int)(randomValue(theGameAudioSeed) % delta)) + lo; + const UnsignedInt delta = hi - lo + 1; +#endif -/**/ -#ifdef DEBUG_RANDOM_AUDIO -DEBUG_LOG(( "%d: GetGameAudioRandomValue = %d (%d - %d), %s line %d", - TheGameLogic->getFrame(), rval, lo, hi, file, line )); + const Int rval = ((Int)(randomValue(theGameLogicSeed) % delta)) + lo; + +#ifdef DEBUG_RANDOM_LOGIC + DEBUG_LOG(( "%d: GetGameLogicRandomValue = %d (%d - %d), %s line %d", + TheGameLogic->getFrame(), rval, lo, hi, file, line )); #endif -/**/ + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } @@ -295,22 +293,25 @@ DEBUG_LOG(( "%d: GetGameAudioRandomValue = %d (%d - %d), %s line %d", // Real GetGameLogicRandomValueReal( Real lo, Real hi, const char *file, int line ) { - Real delta = hi - lo; - Real rval; - +#if RETAIL_COMPATIBLE_CRC + const Real delta = hi - lo; if (delta <= 0.0f) return hi; +#else + if (lo >= hi) + return hi; - rval = ((Real)(randomValue(theGameLogicSeed)) * theMultFactor ) * delta + lo; + const Real delta = hi - lo; +#endif + + const Real rval = ((Real)(randomValue(theGameLogicSeed)) * theMultFactor) * delta + lo; - DEBUG_ASSERTCRASH( rval >= lo && rval <= hi, ("Bad random val")); -/**/ #ifdef DEBUG_RANDOM_LOGIC -DEBUG_LOG(( "%d: GetGameLogicRandomValueReal = %f, %s line %d", - TheGameLogic->getFrame(), rval, file, line )); + DEBUG_LOG(( "%d: GetGameLogicRandomValueReal = %f, %s line %d", + TheGameLogic->getFrame(), rval, file, line )); #endif -/**/ + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } @@ -320,76 +321,57 @@ DEBUG_LOG(( "%d: GetGameLogicRandomValueReal = %f, %s line %d", // The intended use case for this function are randomized values that are desirable to be synchronized across clients, // but should not result in a mismatch if they aren't synchronized; e.g. for scripted audio events. // -Real GetGameLogicRandomValueRealUnchanged( Real lo, Real hi, const char *file, int line ) +Int GetGameLogicRandomValueUnchanged( int lo, int hi, const char *file, int line ) { #if RETAIL_COMPATIBLE_CRC - return GetGameLogicRandomValueReal(lo, hi, file, line); + return GetGameLogicRandomValue(lo, hi, file, line); #endif - const Real delta = hi - lo; - if (delta <= 0.0f) + if (lo >= hi) return hi; UnsignedInt seed[ARRAY_SIZE(theGameLogicSeed)]; memcpy(&seed[0], &theGameLogicSeed[0], sizeof(seed)); - const Real rval = ((Real)(randomValue(seed)) * theMultFactor) * delta + lo; - - DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); + const UnsignedInt delta = hi - lo + 1; + const Int rval = ((Int)(randomValue(seed) % delta)) + lo; #ifdef DEBUG_RANDOM_LOGIC - DEBUG_LOG(( "%d: GetGameLogicRandomValueRealUnchanged = %f, %s line %d", - TheGameLogic->getFrame(), rval, file, line )); + DEBUG_LOG(( "%d: GetGameLogicRandomValueUnchanged = %d (%d - %d), %s line %d", + TheGameLogic->getFrame(), rval, lo, hi, file, line )); #endif + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } // -// Real valued random value +// TheSuperHackers @info This function does not change the seed values with retail compatibility disabled. +// Consecutive calls always return the same value for the same combination of min / max values, assuming the seed values haven't changed in between. +// The intended use case for this function are randomized values that are desirable to be synchronized across clients, +// but should not result in a mismatch if they aren't synchronized; e.g. for scripted audio events. // -Real GetGameClientRandomValueReal( Real lo, Real hi, const char *file, int line ) +Real GetGameLogicRandomValueRealUnchanged( Real lo, Real hi, const char *file, int line ) { - Real delta = hi - lo; - Real rval; - - if (delta <= 0.0f) - return hi; - - rval = ((Real)(randomValue(theGameClientSeed)) * theMultFactor ) * delta + lo; - - DEBUG_ASSERTCRASH( rval >= lo && rval <= hi, ("Bad random val")); -/**/ -#ifdef DEBUG_RANDOM_CLIENT -DEBUG_LOG(( "%d: GetGameClientRandomValueReal = %f, %s line %d", - TheGameLogic->getFrame(), rval, file, line )); +#if RETAIL_COMPATIBLE_CRC + return GetGameLogicRandomValueReal(lo, hi, file, line); #endif -/**/ - return rval; -} - -// -// Real valued random value -// -Real GetGameAudioRandomValueReal( Real lo, Real hi, const char *file, int line ) -{ - Real delta = hi - lo; - Real rval; - - if (delta <= 0.0f) + if (lo >= hi) return hi; - rval = ((Real)(randomValue(theGameAudioSeed)) * theMultFactor ) * delta + lo; + UnsignedInt seed[ARRAY_SIZE(theGameLogicSeed)]; + memcpy(&seed[0], &theGameLogicSeed[0], sizeof(seed)); - DEBUG_ASSERTCRASH( rval >= lo && rval <= hi, ("Bad random val")); -/**/ -#ifdef DEBUG_RANDOM_AUDIO -DEBUG_LOG(( "%d: GetGameAudioRandomValueReal = %f, %s line %d", - TheGameLogic->getFrame(), rval, file, line )); + const Real delta = hi - lo; + const Real rval = ((Real)(randomValue(seed)) * theMultFactor) * delta + lo; + +#ifdef DEBUG_RANDOM_LOGIC + DEBUG_LOG(( "%d: GetGameLogicRandomValueRealUnchanged = %f, %s line %d", + TheGameLogic->getFrame(), rval, file, line )); #endif -/**/ + DEBUG_ASSERTCRASH(rval >= lo && rval <= hi, ("Bad random val")); return rval; } @@ -438,7 +420,6 @@ Real GameClientRandomVariable::getValue() const } } - //-------------------------------------------------------------------------------------------------------------- // GameLogicRandomVariable // @@ -483,5 +464,3 @@ Real GameLogicRandomVariable::getValue() const return 0.0f; } } - -