Hooks
static bool BeforeCvDllGameContext_RandomNumberGeneratorSyncCheck(CvDllGameContext* self, PlayerTypes ePlayer, ICvRandom1* pRandom, bool bIsHost, bool& result);static void AfterCvDllGameContext_RandomNumberGeneratorSyncCheck(CvDllGameContext* self, PlayerTypes ePlayer, ICvRandom1* pRandom, bool bIsHost, bool& result);static bool ReplaceCvDllGameContext_RandomNumberGeneratorSyncCheck(bool (*original)(CvDllGameContext*, PlayerTypes, ICvRandom1*, bool), CvDllGameContext* self, PlayerTypes ePlayer, ICvRandom1* pRandom, bool bIsHost);// CivHooks.h gives this hook point no types, so nothing checks these hooks' parameters.host->RegisterHook(host->pluginIndex, CivHooks::CvDllGameContext_RandomNumberGeneratorSyncCheck::ID, CIV_HOOK_BEFORE, (void*)&BeforeCvDllGameContext_RandomNumberGeneratorSyncCheck);host->RegisterHook(host->pluginIndex, CivHooks::CvDllGameContext_RandomNumberGeneratorSyncCheck::ID, CIV_HOOK_AFTER, (void*)&AfterCvDllGameContext_RandomNumberGeneratorSyncCheck);host->RegisterHook(host->pluginIndex, CivHooks::CvDllGameContext_RandomNumberGeneratorSyncCheck::ID, CIV_HOOK_REPLACE, (void*)&ReplaceCvDllGameContext_RandomNumberGeneratorSyncCheck);
Code
905bool CvDllGameContext::RandomNumberGeneratorSyncCheck(PlayerTypes ePlayer, ICvRandom1* pRandom, bool bIsHost)906{907 // uh oh! Check the Random number generator!908 const CvRandom& localSimRandomNumberGenerator = GC.getGame().getJonRand();909 CvRandom* pkRandom = GC.UnwrapRandomPointer(pRandom);910911 if(localSimRandomNumberGenerator != *pkRandom)912 {913 FILogFile* logFile = LOGFILEMGR.GetLog("net_message_debug.log", 0);914915 char formatBuf[128] = {"\0"};916 std::string rngLogMessage = "Game Random Number Generators are out of sync : local.seed=";917 rngLogMessage += _itoa_s(localSimRandomNumberGenerator.getSeed(), formatBuf, 10);918 rngLogMessage += ", remote.seed=";919 rngLogMessage += _itoa_s(pkRandom->getSeed(), formatBuf, 10);920 rngLogMessage += "\n\tlocal.callCount=";921 rngLogMessage += _itoa_s(localSimRandomNumberGenerator.getCallCount(), formatBuf, 10);922 rngLogMessage += ", remote.callCount=";923 rngLogMessage += _itoa_s(pkRandom->getCallCount(), formatBuf, 10);924 rngLogMessage += "\n\tlocal.resetCount=";925 rngLogMessage += _itoa_s(localSimRandomNumberGenerator.getResetCount(), formatBuf, 10);926 rngLogMessage += ", remote.resetCount=";927 rngLogMessage += _itoa_s(pkRandom->getResetCount(), formatBuf, 10);928 rngLogMessage += "\n";929930 if(localSimRandomNumberGenerator.callStackDebuggingEnabled() && pkRandom->callStackDebuggingEnabled())931 {932 std::string localCallStack("");933 std::string remoteCallStack("");934 localSimRandomNumberGenerator.resolveCallStacks();935 const std::vector<std::string>& localCallStacks = localSimRandomNumberGenerator.getResolvedCallStacks();936 const std::vector<std::string>& remoteCallStacks = pkRandom->getResolvedCallStacks();937 const std::vector<unsigned long>& localSeedHistory = localSimRandomNumberGenerator.getSeedHistory();938 const std::vector<unsigned long>& remoteSeedHistory = pkRandom->getSeedHistory();939 std::vector<unsigned long>::const_iterator localSeedIterator = localSeedHistory.begin();940 std::vector<unsigned long>::const_iterator remoteSeedIterator = remoteSeedHistory.begin();941 unsigned int callNumber = 0;942 for(localSeedIterator = localSeedHistory.begin(), remoteSeedIterator = remoteSeedHistory.begin(); localSeedIterator != localSeedHistory.end() && remoteSeedIterator != remoteSeedHistory.end(); ++localSeedIterator, ++remoteSeedIterator, ++callNumber)943 {944 if(*localSeedIterator != *remoteSeedIterator)945 {946 if(callNumber < localCallStacks.size() && callNumber < remoteCallStacks.size())947 {948 rngLogMessage += "At Call #";949 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);950 rngLogMessage += " random number seeds are different.\n";951 if(callNumber > 0)952 {953 rngLogMessage += "Call #";954 rngLogMessage += _itoa_s(callNumber - 1, formatBuf, 10);955 rngLogMessage += "\nLocal:\n";956 rngLogMessage += localCallStacks[callNumber - 1];957 rngLogMessage += "\nRemote:\n";958 rngLogMessage += remoteCallStacks[callNumber - 1];959 }960 rngLogMessage += "Call #";961 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);962 rngLogMessage += "\nLocal:\n";963 rngLogMessage += localCallStacks[callNumber];964 rngLogMessage += "\nRemote:\n";965 rngLogMessage += remoteCallStacks[callNumber];966 break;967 }968 }969 }970 if(localSeedIterator != localSeedHistory.end() && remoteSeedIterator == remoteSeedHistory.end())971 {972 rngLogMessage += "\nLocal random number generator called more than remote at call #";973 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);974 rngLogMessage += "\n";975 if(callNumber < localSeedHistory.size())976 {977 rngLogMessage += "Local CallStack:\n";978 rngLogMessage += localCallStacks[callNumber];979 }980 }981 else if(remoteSeedIterator != remoteSeedHistory.end() && localSeedIterator == localSeedHistory.end())982 {983 rngLogMessage += "\nremote random number generator called more than local at call #";984 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);985 rngLogMessage += "\n";986 if(callNumber < remoteSeedHistory.size())987 {988 rngLogMessage += "remote CallStack:\n";989 rngLogMessage += remoteCallStacks[callNumber];990 }991 }992993 // find first different call994 std::vector<std::string>::const_iterator localCallStackIterator;995 std::vector<std::string>::const_iterator remoteCallStackIterator;996 for(localCallStackIterator = localCallStacks.begin(), remoteCallStackIterator = remoteCallStacks.begin(), callNumber = 0; localCallStackIterator != localCallStacks.end() && remoteCallStackIterator != remoteCallStacks.end(); ++localCallStackIterator, ++remoteCallStackIterator, ++callNumber)997 {998 if(*localCallStackIterator != *remoteCallStackIterator)999 {1000 rngLogMessage += "\nFirst different callstack at call #";1001 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);1002 rngLogMessage += "\n";1003 rngLogMessage += "Local :\n";1004 rngLogMessage += *localCallStackIterator;1005 rngLogMessage += "Remote :\n";1006 rngLogMessage += *remoteCallStackIterator;1007 break;1008 }1009 }10101011 if(logFile)1012 {1013 logFile->DebugMsg(rngLogMessage.c_str());1014 }10151016 CvAssertMsg(false, rngLogMessage.c_str());10171018 if(logFile)1019 {1020 rngLogMessage = "\nDebug dump:\n";102110221023 // add full history1024 rngLogMessage += "Seed History -\n";1025 localSeedIterator = localSeedHistory.begin();1026 remoteSeedIterator = remoteSeedHistory.begin();1027 callNumber = 0;1028 while(localSeedIterator != localSeedHistory.end() || remoteSeedIterator != remoteSeedHistory.end())1029 {1030 ++callNumber;1031 rngLogMessage += "\t Call #";1032 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);1033 rngLogMessage += " LOCAL=";1034 if(localSeedIterator != localSeedHistory.end())1035 {1036 rngLogMessage += _itoa_s(*localSeedIterator, formatBuf, 10);1037 ++localSeedIterator;1038 }1039 rngLogMessage += "\tREMOTE=";1040 if(remoteSeedIterator != remoteSeedHistory.end())1041 {1042 rngLogMessage += _itoa_s(*remoteSeedIterator, formatBuf, 10);1043 ++remoteSeedIterator;1044 }1045 rngLogMessage += "\n";1046 }10471048 rngLogMessage += "\nLocal callstack history\n";1049 callNumber = 0;1050 std::string lastCallStackLogged;1051 unsigned int repeatCount = 0;1052 std::vector<std::string>::const_iterator i;1053 for(i = localCallStacks.begin(); i != localCallStacks.end(); ++i)1054 {1055 if(lastCallStackLogged != *i)1056 {1057 if(repeatCount > 0)1058 {1059 rngLogMessage += "Last message repeated ";1060 rngLogMessage += _itoa_s(repeatCount, formatBuf, 10);1061 rngLogMessage += " times\n";1062 }1063 rngLogMessage += "Call #";1064 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);1065 rngLogMessage += "\n";1066 rngLogMessage += *i;1067 lastCallStackLogged = *i;1068 repeatCount = 0;1069 }1070 else1071 {1072 repeatCount++;1073 }1074 ++callNumber;1075 }10761077 rngLogMessage += "\nRemote callstack history\n";1078 callNumber = 0;1079 repeatCount = 0;1080 for(i = remoteCallStacks.begin(); i != remoteCallStacks.end(); ++i)1081 {1082 if(lastCallStackLogged != *i)1083 {1084 if(repeatCount > 0)1085 {1086 rngLogMessage += "Last message repeated ";1087 rngLogMessage += _itoa_s(repeatCount, formatBuf, 10);1088 rngLogMessage += " times\n";1089 }1090 rngLogMessage += "Call #";1091 rngLogMessage += _itoa_s(callNumber, formatBuf, 10);1092 rngLogMessage += "\n";1093 rngLogMessage += *i;1094 lastCallStackLogged = *i;1095 repeatCount = 0;1096 }1097 else1098 {1099 repeatCount++;1100 }1101 ++callNumber;1102 }1103 logFile->DebugMsg(rngLogMessage.c_str());1104 }11051106 }1107 else1108 {1109 if(logFile)1110 {1111 logFile->DebugMsg(rngLogMessage.c_str());1112 }1113 CvAssertMsg(false, rngLogMessage.c_str());1114 }111511161117 /* If this point has been reached, the OOS may be nearly unrecoverable1118 // attempt to recover1119 if(m_isHost)1120 {1121 CvRandom & rng = auto_ptr<ICvGame1> pGame = GameCore::GetGame();\n.getJonRand();1122 rng.reset(m_simRandomNumberGenerator.getSeed());1123 }1124 // brute force approach1125 // JAR : todo - this is the solution of last resort if1126 // loadDelta() doesn't work out1127 */1128 return false;1129 }11301131 return true;1132}