slowdown and speedup clients based on recorded stats

This commit is contained in:
Titus Tscharntke 2013-04-07 15:27:55 +00:00
parent e8e7b96865
commit 4a436066e7
5 changed files with 134 additions and 24 deletions

View File

@ -74,6 +74,7 @@ Game::Game() : ProgramState(NULL) {
lastUpdateFps=0;
avgUpdateFps=0;
framesToCatchUpAsClient=0;
framesToSlowDownAsClient=0;
totalRenderFps=0;
renderFps=0;
lastRenderFps=0;
@ -161,6 +162,10 @@ Game::Game() : ProgramState(NULL) {
lastNetworkPlayerConnectionCheck = time(NULL);
inJoinGameLoading = false;
for( int i=0;i<GameConstants::networkSmoothInterval;i++){
frameWhenMessageWasReceived[i]==-1;
framesNeededToWaitForServerMessage[i]==-1;
}
fadeMusicMilliseconds = Config::getInstance().getInt("GameStartStopFadeSoundMilliseconds",intToStr(fadeMusicMilliseconds).c_str());
GAME_STATS_DUMP_INTERVAL = Config::getInstance().getInt("GameStatsDumpIntervalSeconds",intToStr(GAME_STATS_DUMP_INTERVAL).c_str());
@ -235,6 +240,7 @@ void Game::resetMembers() {
renderFps=0;
lastUpdateFps=0;
framesToCatchUpAsClient=0;
framesToSlowDownAsClient=0;
lastRenderFps=-1;
avgUpdateFps=-1;
avgRenderFps=-1;
@ -266,6 +272,12 @@ void Game::resetMembers() {
inJoinGameLoading = false;
for( int i=0;i<GameConstants::networkSmoothInterval;i++){
frameWhenMessageWasReceived[i]==-1;
framesNeededToWaitForServerMessage[i]==-1;
}
fadeMusicMilliseconds = Config::getInstance().getInt("GameStartStopFadeSoundMilliseconds",intToStr(fadeMusicMilliseconds).c_str());
GAME_STATS_DUMP_INTERVAL = Config::getInstance().getInt("GameStatsDumpIntervalSeconds",intToStr(GAME_STATS_DUMP_INTERVAL).c_str());
@ -1733,39 +1745,113 @@ void Game::update() {
ClientInterface *clientInterface = dynamic_cast<ClientInterface *>(networkManager.getClientInterface());
if(clientInterface != NULL) {
uint64 lastNetworkFrameFromServer = clientInterface->getCachedLastPendingFrameCount();
// if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > (world.getFrameCount() + gameSettings.getNetworkFramePeriod())+1) {
// //if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > world.getFrameCount()) {
// int frameDifference = ((lastNetworkFrameFromServer - world.getFrameCount()) / gameSettings.getNetworkFramePeriod()) * gameSettings.getNetworkFramePeriod();
//
// //int frameDifference = lastNetworkFrameFromServer - world.getFrameCount();
if(framesToCatchUpAsClient==0){
if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > (world.getFrameCount() + gameSettings.getNetworkFramePeriod()/4)) {
//if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > world.getFrameCount()) {
int frameDifference = lastNetworkFrameFromServer - world.getFrameCount();
printf("Client will speed up: %d frames lastNetworkFrameFromServer: %lld world.getFrameCount() = %d updateLoops = %d\n",frameDifference,(long long int)lastNetworkFrameFromServer,world.getFrameCount(),updateLoops);
framesToCatchUpAsClient=frameDifference;
// done below now: updateLoops += frameDifference;
//// if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > (world.getFrameCount() + gameSettings.getNetworkFramePeriod())+1) {
//// //if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > world.getFrameCount()) {
//// int frameDifference = ((lastNetworkFrameFromServer - world.getFrameCount()) / gameSettings.getNetworkFramePeriod()) * gameSettings.getNetworkFramePeriod();
////
//// //int frameDifference = lastNetworkFrameFromServer - world.getFrameCount();
// if(framesToCatchUpAsClient==0){
// if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > (world.getFrameCount() + gameSettings.getNetworkFramePeriod()/4)) {
// //if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > world.getFrameCount()) {
// int frameDifference = lastNetworkFrameFromServer - world.getFrameCount();
// printf("Client will speed up: %d frames lastNetworkFrameFromServer: %lld world.getFrameCount() = %d updateLoops = %d\n",frameDifference,(long long int)lastNetworkFrameFromServer,world.getFrameCount(),updateLoops);
// framesToCatchUpAsClient=frameDifference;
// // done below now: updateLoops += frameDifference;
// }
// }
//// //If client is ahead maybe this fixes it ( by titi ):
// if(updateLoops!=0 && lastNetworkFrameFromServer > 0 && world.getFrameCount() > lastNetworkFrameFromServer && (world.getFrameCount()%GameConstants::updateFps)>38 ){
// printf("Client will slow down because no message has arrived yet. currentFrame=%d \n",world.getFrameCount());
// updateLoops = 0;
// }
/////////////////////////////////
// TTTT new attempt to make things smoother:
///////////////
////////////////////////////////////////////
//get stats of received/waiting for packages
////////////////////////////////////////////
// calculate current receive Index slot:
int index = (world.getFrameCount()
- (world.getFrameCount()
% gameSettings.getNetworkFramePeriod())
/ gameSettings.getNetworkFramePeriod())
% GameConstants::networkSmoothInterval;
if(frameWhenMessageWasReceived[index]==-1){
// we need to check if we already received something for next frame
if(lastNetworkFrameFromServer > 0 && lastNetworkFrameFromServer > world.getFrameCount()) {
frameWhenMessageWasReceived[index]= lastNetworkFrameFromServer-world.getFrameCount();
}
}
// //If client is ahead maybe this fixes it ( by titi ):
if(updateLoops!=0 && lastNetworkFrameFromServer > 0 && world.getFrameCount() > lastNetworkFrameFromServer && (world.getFrameCount()%GameConstants::updateFps)>38 ){
printf("Client will slow down because no message has arrived yet. currentFrame=%d \n",world.getFrameCount());
updateLoops = 0;
if(frameWhenMessageWasReceived[index]==-1){
// calc time waiting for message in milliseconds to frames
framesNeededToWaitForServerMessage[index]=clientInterface->getTimeClientWaitedForLastMessage()/1000/GameConstants::updateFps;
}
////////////////////////////////////////////
//use the recorded stats of received/waiting for packages
////////////////////////////////////////////
//lets see if the client is in front and had to wait for messages ...
//lets see if all last recorded frames where received too early
int minimum=0;
int allowedMaxFallback=5;
int countOfMessagesReceivedTooEarly=0;
int countOfMessagesReceivedTooLate=0;
int sumOfTooLateFrames=0;
bool cleanupStats=false;
for( int i=0;i<GameConstants::networkSmoothInterval;i++){
if(frameWhenMessageWasReceived[i]>allowedMaxFallback){
countOfMessagesReceivedTooEarly++;
if ( minimum == 0 || minimum > frameWhenMessageWasReceived[i] ){
minimum=frameWhenMessageWasReceived[i];
}
}
if(framesNeededToWaitForServerMessage[i]>0){
countOfMessagesReceivedTooLate++;
sumOfTooLateFrames+=framesNeededToWaitForServerMessage[i];
}
}
if( countOfMessagesReceivedTooEarly==GameConstants::networkSmoothInterval )
{// all packages where too early
// we catch up the minimum-catchupInterval of what we recorded
framesToCatchUpAsClient=minimum-allowedMaxFallback;
framesToSlowDownAsClient=0;
cleanupStats=true;
printf("Worldframe %d : Client will speed up: %d frames\n",world.getFrameCount(),framesToCatchUpAsClient);
}
else if(countOfMessagesReceivedTooLate>3){
framesToSlowDownAsClient=sumOfTooLateFrames/countOfMessagesReceivedTooLate;
framesToCatchUpAsClient=0;
cleanupStats=true;
printf("Worldframe %d : Client will slow down: %d frames\n",world.getFrameCount(),framesToCatchUpAsClient);
}
if(cleanupStats==true) {
// Once we decided to use the stats to do some correction, we reset/cleanup our recorded stats
for( int i=0;i<GameConstants::networkSmoothInterval;i++){
frameWhenMessageWasReceived[i]=-1;
framesNeededToWaitForServerMessage[index]=-1;
}
}
}
}
// we catch up a bit smoother with updateLoops = 2
if(framesToCatchUpAsClient>0)
{
if(framesToCatchUpAsClient==1)
{
//ignore it and don't catch up this one frame
framesToCatchUpAsClient=0;
}
else if(framesToCatchUpAsClient>1){
updateLoops = 2;
framesToCatchUpAsClient=framesToCatchUpAsClient-2;
}
framesToCatchUpAsClient=framesToCatchUpAsClient-1;
}
if(framesToSlowDownAsClient>0)
{// slowdown still the hard way.
updateLoops = 0;
framesToSlowDownAsClient=framesToSlowDownAsClient-1;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chrono.getMillis());

View File

@ -88,6 +88,9 @@ private:
int updateFps, lastUpdateFps, avgUpdateFps;
int framesToCatchUpAsClient;
int framesToSlowDownAsClient;
int frameWhenMessageWasReceived[GameConstants::networkSmoothInterval];
int framesNeededToWaitForServerMessage[GameConstants::networkSmoothInterval];
int totalRenderFps, renderFps, lastRenderFps, avgRenderFps,currentAvgRenderFpsTotal;
uint64 tickCount;
bool paused;

View File

@ -133,6 +133,7 @@ public:
static int networkFramePeriod;
static const int networkPingInterval = 5;
static const int networkSmoothInterval= 30;
//static const int networkExtraLatency= 200;
static const int maxClientConnectHandshakeSecs= 10;

View File

@ -166,6 +166,7 @@ ClientInterface::ClientInterface() : GameNetworkInterface() {
networkCommandListThread = NULL;
cachedPendingCommandsIndex = 0;
cachedLastPendingFrameCount = 0;
timeClientWaitedForLastMessage = 0;
flagAccessor = new Mutex(CODE_AT_LINE);
@ -1190,6 +1191,16 @@ uint64 ClientInterface::getCachedLastPendingFrameCount() {
return result;
}
int64 ClientInterface::getTimeClientWaitedForLastMessage() {
MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
uint64 result = timeClientWaitedForLastMessage;
safeMutex.ReleaseLock();
return result;
}
//void ClientInterface::simpleTask(BaseThread *callingThread) {
// Chrono chrono;
// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
@ -1211,6 +1222,8 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
bool waitForData = false;
uint64 copyCachedLastPendingFrameCount = 0;
uint64 waitCount = 0;
Chrono chrono;
timeClientWaitedForLastMessage = 0;
if(quit == false && this->quitThread == false) {
//MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
@ -1236,6 +1249,10 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
//cachedPendingCommands.erase(frameCount);
cachedPendingCommands[frameCount].clear();
}
if(waitForData == true) {
timeClientWaitedForLastMessage=chrono.getMillis();
chrono.stop();
}
safeMutex.ReleaseLock(true);
result = true;
@ -1250,6 +1267,7 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
if(waitForData == false) {
printf("Client waiting for packet for frame: %d, copyCachedLastPendingFrameCount = %lld\n",frameCount,(long long int)copyCachedLastPendingFrameCount);
chrono.start();
}
if(copyCachedLastPendingFrameCount > frameCount) {
break;

View File

@ -87,6 +87,7 @@ private:
std::map<int,Commands> cachedPendingCommands; //commands ready to be given
uint64 cachedPendingCommandsIndex;
uint64 cachedLastPendingFrameCount;
int64 timeClientWaitedForLastMessage;
Mutex *flagAccessor;
bool joinGameInProgress;
@ -112,6 +113,7 @@ public:
void sendResumeGameMessage();
uint64 getCachedLastPendingFrameCount();
int64 getTimeClientWaitedForLastMessage();
//message processing
virtual void update();