2010-03-17 07:25:19 +01:00
// ==============================================================
// This file is part of Glest (www.glest.org)
//
2010-03-23 02:38:19 +01:00
// Copyright (C) 2001-2008 Marti<74> o Figueroa
2010-03-17 07:25:19 +01:00
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
# include "server_interface.h"
# include <cassert>
# include <stdexcept>
# include "platform_util.h"
# include "conversion.h"
# include "config.h"
# include "lang.h"
# include "logger.h"
# include <time.h>
2010-03-20 00:26:00 +01:00
# include "util.h"
# include "leak_dumper.h"
2010-03-17 07:25:19 +01:00
using namespace std ;
using namespace Shared : : Platform ;
using namespace Shared : : Util ;
namespace Glest { namespace Game {
// =====================================================
// class ServerInterface
// =====================================================
2010-06-03 09:52:17 +02:00
// Experimental threading of broadcasts to clients
2010-06-03 23:55:17 +02:00
//bool enabledThreadedClientCommandBroadcast = true;
bool enabledThreadedClientCommandBroadcast = false ;
2010-06-03 09:52:17 +02:00
2010-06-15 07:36:07 +02:00
// The maximum amount of network update iterations a client is allowed to fall behind
2010-07-01 02:08:59 +02:00
double maxFrameCountLagAllowed = 30 ;
2010-06-30 09:03:04 +02:00
// The maximum amount of seconds a client is allowed to not communicate with the server
2010-07-01 02:08:59 +02:00
double maxClientLagTimeAllowed = 20 ;
2010-06-30 09:03:04 +02:00
2010-08-27 20:53:59 +02:00
// The maximum amount of network update iterations a client is allowed to fall behind before we
// for a disconnect regardless of other settings
double maxFrameCountLagAllowedEver = 75 ;
2010-06-17 02:08:27 +02:00
// 65% of max we warn all users about the lagged client
double warnFrameCountLagPercent = 0.65 ;
2010-06-17 23:46:36 +02:00
// Should we wait for lagged clients instead of disconnect them?
2010-07-16 18:53:19 +02:00
//bool pauseGameForLaggedClients = false;
2010-06-15 07:36:07 +02:00
2010-06-28 02:21:12 +02:00
// Seconds grace period before we start checking LAG
double LAG_CHECK_GRACE_PERIOD = 15 ;
2010-08-07 05:26:38 +02:00
// The max amount of time to 'freeze' gameplay per packet when a client is lagging
// badly and we want to give time for them to catch up
double MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = 2 ;
2010-03-17 07:25:19 +01:00
ServerInterface : : ServerInterface ( ) {
gameHasBeenInitiated = false ;
gameSettingsUpdateCount = 0 ;
2010-06-15 07:36:07 +02:00
currentFrameCount = 0 ;
2010-06-28 02:21:12 +02:00
gameStartTime = 0 ;
2010-03-17 07:25:19 +01:00
2010-06-12 20:27:39 +02:00
enabledThreadedClientCommandBroadcast = Config : : getInstance ( ) . getBool ( " EnableThreadedClientCommandBroadcast " , " false " ) ;
2010-06-15 07:36:07 +02:00
maxFrameCountLagAllowed = Config : : getInstance ( ) . getInt ( " MaxFrameCountLagAllowed " , intToStr ( maxFrameCountLagAllowed ) . c_str ( ) ) ;
2010-08-27 20:53:59 +02:00
maxFrameCountLagAllowedEver = Config : : getInstance ( ) . getInt ( " MaxFrameCountLagAllowedEver " , intToStr ( maxFrameCountLagAllowedEver ) . c_str ( ) ) ;
2010-06-30 09:03:04 +02:00
maxClientLagTimeAllowed = Config : : getInstance ( ) . getInt ( " MaxClientLagTimeAllowed " , intToStr ( maxClientLagTimeAllowed ) . c_str ( ) ) ;
2010-06-17 02:08:27 +02:00
warnFrameCountLagPercent = Config : : getInstance ( ) . getFloat ( " WarnFrameCountLagPercent " , doubleToStr ( warnFrameCountLagPercent ) . c_str ( ) ) ;
2010-08-27 20:53:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] enabledThreadedClientCommandBroadcast = %d, maxFrameCountLagAllowed = %f, maxFrameCountLagAllowedEver = %f, maxClientLagTimeAllowed = %f \n " , __FILE__ , __FUNCTION__ , __LINE__ , enabledThreadedClientCommandBroadcast , maxFrameCountLagAllowed , maxFrameCountLagAllowedEver , maxClientLagTimeAllowed ) ;
2010-06-12 20:27:39 +02:00
2010-03-17 07:25:19 +01:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
slots [ i ] = NULL ;
2010-04-29 01:59:37 +02:00
switchSetupRequests [ i ] = NULL ;
2010-03-17 07:25:19 +01:00
}
serverSocket . setBlock ( false ) ;
2010-06-24 03:23:18 +02:00
//serverSocket.bind(Config::getInstance().getInt("ServerPort",intToStr(GameConstants::serverPort).c_str()));
serverSocket . setBindPort ( Config : : getInstance ( ) . getInt ( " ServerPort " , intToStr ( GameConstants : : serverPort ) . c_str ( ) ) ) ;
2010-03-17 07:25:19 +01:00
}
ServerInterface : : ~ ServerInterface ( ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
delete slots [ i ] ;
2010-04-29 01:59:37 +02:00
slots [ i ] = NULL ;
2010-07-01 08:11:14 +02:00
2010-04-29 01:59:37 +02:00
delete switchSetupRequests [ i ] ;
switchSetupRequests [ i ] = NULL ;
2010-03-17 07:25:19 +01:00
}
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
close ( ) ;
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
}
void ServerInterface : : addSlot ( int playerIndex ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
assert ( playerIndex > = 0 & & playerIndex < GameConstants : : maxPlayers ) ;
2010-08-21 03:52:41 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
2010-06-24 03:23:18 +02:00
if ( serverSocket . isPortBound ( ) = = false ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-24 03:23:18 +02:00
serverSocket . bind ( serverSocket . getBindPort ( ) ) ;
}
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
delete slots [ playerIndex ] ;
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
slots [ playerIndex ] = new ConnectionSlot ( this , playerIndex ) ;
2010-07-01 08:11:14 +02:00
2010-08-21 03:52:41 +02:00
safeMutex . ReleaseLock ( ) ;
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
updateListen ( ) ;
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
}
2010-04-30 03:08:29 +02:00
bool ServerInterface : : switchSlot ( int fromPlayerIndex , int toPlayerIndex ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-04-30 03:08:29 +02:00
bool result = false ;
assert ( fromPlayerIndex > = 0 & & fromPlayerIndex < GameConstants : : maxPlayers ) ;
assert ( toPlayerIndex > = 0 & & toPlayerIndex < GameConstants : : maxPlayers ) ;
if ( fromPlayerIndex = = toPlayerIndex ) return false ; // doubleclicked or whatever
//printf(" checking if slot %d is free?\n",toPlayerIndex);
2010-08-21 03:52:41 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
if ( slots [ toPlayerIndex ] - > isConnected ( ) = = false ) {
2010-04-30 03:08:29 +02:00
//printf(" yes, its free :)\n");
slots [ fromPlayerIndex ] - > setPlayerIndex ( toPlayerIndex ) ;
2010-04-30 20:36:38 +02:00
slots [ toPlayerIndex ] - > setPlayerIndex ( fromPlayerIndex ) ;
2010-04-30 03:08:29 +02:00
ConnectionSlot * tmp = slots [ toPlayerIndex ] ;
slots [ toPlayerIndex ] = slots [ fromPlayerIndex ] ;
slots [ fromPlayerIndex ] = tmp ;
2010-08-21 03:52:41 +02:00
safeMutex . ReleaseLock ( ) ;
2010-04-30 03:08:29 +02:00
PlayerIndexMessage playerIndexMessage ( toPlayerIndex ) ;
slots [ toPlayerIndex ] - > sendMessage ( & playerIndexMessage ) ;
result = true ;
2010-04-30 20:36:38 +02:00
updateListen ( ) ;
2010-04-30 03:08:29 +02:00
}
2010-08-21 03:52:41 +02:00
else {
safeMutex . ReleaseLock ( ) ;
}
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-04-30 03:08:29 +02:00
return result ;
}
2010-05-15 20:59:17 +02:00
void ServerInterface : : removeSlot ( int playerIndex ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
2010-08-21 03:52:41 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
2010-07-01 08:11:14 +02:00
// Mention to everyone that this player is disconnected
ConnectionSlot * slot = slots [ playerIndex ] ;
bool notifyDisconnect = false ;
char szBuf [ 4096 ] = " " ;
if ( slot ! = NULL ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
if ( slot - > getLastReceiveCommandListTime ( ) > 0 ) {
const char * msgTemplate = " Player %s, disconnected from the game. " ;
# ifdef WIN32
_snprintf ( szBuf , 4095 , msgTemplate , slot - > getName ( ) . c_str ( ) ) ;
# else
snprintf ( szBuf , 4095 , msgTemplate , slot - > getName ( ) . c_str ( ) ) ;
# endif
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] %s \n " , __FILE__ , __FUNCTION__ , __LINE__ , szBuf ) ;
notifyDisconnect = true ;
}
}
2010-05-15 20:59:17 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
2010-03-17 07:25:19 +01:00
delete slots [ playerIndex ] ;
slots [ playerIndex ] = NULL ;
2010-05-15 20:59:17 +02:00
2010-08-21 03:52:41 +02:00
safeMutex . ReleaseLock ( ) ;
2010-05-15 20:59:17 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
2010-03-17 07:25:19 +01:00
updateListen ( ) ;
2010-05-15 20:59:17 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
2010-07-01 08:11:14 +02:00
if ( notifyDisconnect = = true ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
string sMsg = szBuf ;
sendTextMessage ( sMsg , - 1 , true ) ;
}
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d playerIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , playerIndex ) ;
2010-03-17 07:25:19 +01:00
}
ConnectionSlot * ServerInterface : : getSlot ( int playerIndex ) {
return slots [ playerIndex ] ;
}
2010-05-17 08:41:05 +02:00
bool ServerInterface : : hasClientConnection ( ) {
bool result = false ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
if ( slots [ i ] ! = NULL & & slots [ i ] - > isConnected ( ) = = true ) {
result = true ;
break ;
}
}
return result ;
}
2010-03-17 07:25:19 +01:00
int ServerInterface : : getConnectedSlotCount ( ) {
int connectedSlotCount = 0 ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
if ( slots [ i ] ! = NULL ) {
+ + connectedSlotCount ;
}
}
return connectedSlotCount ;
}
2010-05-15 20:59:17 +02:00
void ServerInterface : : slotUpdateTask ( ConnectionSlotEvent * event ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
if ( event ! = NULL ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-03 09:52:17 +02:00
2010-06-03 23:49:41 +02:00
if ( event - > eventType = = eSendSocketData ) {
2010-06-03 23:25:33 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] before sendMessage, event->networkMessage = %p \n " , __FILE__ , __FUNCTION__ , event - > networkMessage ) ;
2010-07-01 08:11:14 +02:00
2010-06-03 09:52:17 +02:00
event - > connectionSlot - > sendMessage ( event - > networkMessage ) ;
}
2010-06-03 23:49:41 +02:00
else if ( event - > eventType = = eReceiveSocketData ) {
2010-06-03 09:52:17 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
updateSlot ( event ) ;
}
2010-05-15 20:59:17 +02:00
}
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
}
2010-05-28 01:46:38 +02:00
//
// WARNING!!! This method is executed from the slot worker threads so be careful
// what we do here (things need to be thread safe)
//
2010-05-15 20:59:17 +02:00
void ServerInterface : : updateSlot ( ConnectionSlotEvent * event ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
if ( event ! = NULL ) {
ConnectionSlot * connectionSlot = event - > connectionSlot ;
bool & socketTriggered = event - > socketTriggered ;
bool checkForNewClients = true ;
if ( connectionSlot ! = NULL & &
( gameHasBeenInitiated = = false | | ( connectionSlot - > getSocket ( ) ! = NULL & & socketTriggered = = true ) ) ) {
if ( connectionSlot - > isConnected ( ) = = false | | socketTriggered = = true ) {
if ( gameHasBeenInitiated ) SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] socketTriggeredList[i] = %i \n " , __FILE__ , __FUNCTION__ , ( socketTriggered ? 1 : 0 ) ) ;
if ( connectionSlot - > isConnected ( ) ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] about to call connectionSlot->update() for socketId = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , connectionSlot - > getSocket ( ) - > getSocketId ( ) ) ;
}
else {
if ( gameHasBeenInitiated ) SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] getSocket() == NULL \n " , __FILE__ , __FUNCTION__ ) ;
}
connectionSlot - > update ( checkForNewClients ) ;
// This means no clients are trying to connect at the moment
if ( connectionSlot ! = NULL & & connectionSlot - > getSocket ( ) = = NULL ) {
checkForNewClients = false ;
}
}
}
}
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
}
2010-06-15 07:36:07 +02:00
// Only call when client has just sent us data
2010-08-07 05:26:38 +02:00
std : : pair < bool , bool > ServerInterface : : clientLagCheck ( ConnectionSlot * connectionSlot , bool skipNetworkBroadCast ) {
2010-07-29 07:51:50 +02:00
std : : pair < bool , bool > clientLagExceededOrWarned = std : : make_pair ( false , false ) ;
2010-06-17 02:08:27 +02:00
2010-07-01 08:11:14 +02:00
static bool alreadyInLagCheck = false ;
if ( alreadyInLagCheck = = true ) {
2010-07-29 07:51:50 +02:00
return clientLagExceededOrWarned ;
2010-07-01 08:11:14 +02:00
}
try {
alreadyInLagCheck = true ;
if ( difftime ( time ( NULL ) , gameStartTime ) > = LAG_CHECK_GRACE_PERIOD ) {
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = true ) {
double clientLag = this - > getCurrentFrameCount ( ) - connectionSlot - > getCurrentFrameCount ( ) ;
double clientLagCount = ( gameSettings . getNetworkFramePeriod ( ) > 0 ? ( clientLag / gameSettings . getNetworkFramePeriod ( ) ) : 0 ) ;
connectionSlot - > setCurrentLagCount ( clientLagCount ) ;
double clientLagTime = difftime ( time ( NULL ) , connectionSlot - > getLastReceiveCommandListTime ( ) ) ;
if ( this - > getCurrentFrameCount ( ) > 0 ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] playerIndex = %d, clientLag = %f, clientLagCount = %f, this->getCurrentFrameCount() = %d, connectionSlot->getCurrentFrameCount() = %d, clientLagTime = %f \n " ,
__FILE__ , __FUNCTION__ , __LINE__ ,
connectionSlot - > getPlayerIndex ( ) , clientLag , clientLagCount ,
this - > getCurrentFrameCount ( ) , connectionSlot - > getCurrentFrameCount ( ) , clientLagTime ) ;
2010-06-28 02:21:12 +02:00
}
2010-07-01 08:11:14 +02:00
// TEST LAG Error and warnings!!!
//clientLagCount = maxFrameCountLagAllowed + 1;
//clientLagTime = maxClientLagTimeAllowed + 1;
/*
if ( difftime ( time ( NULL ) , gameStartTime ) > = LAG_CHECK_GRACE_PERIOD + 5 ) {
clientLagTime = maxClientLagTimeAllowed + 1 ;
2010-06-28 02:21:12 +02:00
}
2010-07-01 08:11:14 +02:00
else if ( difftime ( time ( NULL ) , gameStartTime ) > = LAG_CHECK_GRACE_PERIOD ) {
clientLagTime = ( maxClientLagTimeAllowed * warnFrameCountLagPercent ) + 1 ;
}
*/
// END test
2010-06-28 02:21:12 +02:00
2010-07-01 08:11:14 +02:00
// New lag check
if ( ( maxFrameCountLagAllowed > 0 & & clientLagCount > maxFrameCountLagAllowed ) | |
2010-08-27 20:53:59 +02:00
( maxClientLagTimeAllowed > 0 & & clientLagTime > maxClientLagTimeAllowed ) | |
( maxFrameCountLagAllowedEver > 0 & & clientLagCount > maxFrameCountLagAllowedEver ) ) {
2010-07-29 07:51:50 +02:00
clientLagExceededOrWarned . first = true ;
2010-06-28 02:21:12 +02:00
char szBuf [ 4096 ] = " " ;
2010-06-30 09:03:04 +02:00
2010-07-01 08:11:14 +02:00
const char * msgTemplate = " DROPPING %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], disconnecting client. " ;
2010-08-27 20:53:59 +02:00
if ( gameSettings . getNetworkPauseGameForLaggedClients ( ) = = true & &
( maxFrameCountLagAllowedEver < = 0 | | clientLagCount < = maxFrameCountLagAllowedEver ) ) {
2010-07-01 08:11:14 +02:00
msgTemplate = " PAUSING GAME TEMPORARILY for %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], waiting for client to catch up... " ;
}
# ifdef WIN32
_snprintf ( szBuf , 4095 , msgTemplate , connectionSlot - > getName ( ) . c_str ( ) , maxFrameCountLagAllowed , maxClientLagTimeAllowed , clientLagCount , clientLagTime ) ;
# else
2010-06-30 09:03:04 +02:00
snprintf ( szBuf , 4095 , msgTemplate , connectionSlot - > getName ( ) . c_str ( ) , maxFrameCountLagAllowed , maxClientLagTimeAllowed , clientLagCount , clientLagTime ) ;
2010-07-01 08:11:14 +02:00
# endif
2010-06-28 02:21:12 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] %s \n " , __FILE__ , __FUNCTION__ , __LINE__ , szBuf ) ;
2010-08-07 05:26:38 +02:00
if ( skipNetworkBroadCast = = false ) {
string sMsg = szBuf ;
sendTextMessage ( sMsg , - 1 , true ) ;
}
2010-07-01 08:11:14 +02:00
2010-08-27 20:53:59 +02:00
if ( gameSettings . getNetworkPauseGameForLaggedClients ( ) = = false | |
( maxFrameCountLagAllowedEver > 0 & & clientLagCount > maxFrameCountLagAllowedEver ) ) {
2010-07-01 08:11:14 +02:00
connectionSlot - > close ( ) ;
}
}
// New lag check warning
else if ( ( maxFrameCountLagAllowed > 0 & & warnFrameCountLagPercent > 0 & &
clientLagCount > ( maxFrameCountLagAllowed * warnFrameCountLagPercent ) ) | |
( maxClientLagTimeAllowed > 0 & & warnFrameCountLagPercent > 0 & &
clientLagTime > ( maxClientLagTimeAllowed * warnFrameCountLagPercent ) ) ) {
2010-07-29 07:51:50 +02:00
clientLagExceededOrWarned . second = true ;
2010-07-01 08:11:14 +02:00
if ( connectionSlot - > getLagCountWarning ( ) = = false ) {
connectionSlot - > setLagCountWarning ( true ) ;
char szBuf [ 4096 ] = " " ;
const char * msgTemplate = " LAG WARNING for %s, may exceed max allowed LAG count of %f [time = %f], clientLag = %f [%f], WARNING... " ;
# ifdef WIN32
_snprintf ( szBuf , 4095 , msgTemplate , connectionSlot - > getName ( ) . c_str ( ) , maxFrameCountLagAllowed , maxClientLagTimeAllowed , clientLagCount , clientLagTime ) ;
# else
snprintf ( szBuf , 4095 , msgTemplate , connectionSlot - > getName ( ) . c_str ( ) , maxFrameCountLagAllowed , maxClientLagTimeAllowed , clientLagCount , clientLagTime ) ;
# endif
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] %s \n " , __FILE__ , __FUNCTION__ , __LINE__ , szBuf ) ;
2010-08-07 05:26:38 +02:00
if ( skipNetworkBroadCast = = false ) {
string sMsg = szBuf ;
sendTextMessage ( sMsg , - 1 , true ) ;
}
2010-07-01 08:11:14 +02:00
}
}
else if ( connectionSlot - > getLagCountWarning ( ) = = true ) {
connectionSlot - > setLagCountWarning ( false ) ;
2010-06-28 02:21:12 +02:00
}
2010-06-17 02:08:27 +02:00
}
}
2010-06-15 07:36:07 +02:00
}
2010-07-01 08:11:14 +02:00
catch ( const exception & ex ) {
alreadyInLagCheck = false ;
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ERROR [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
throw runtime_error ( ex . what ( ) ) ;
}
alreadyInLagCheck = false ;
2010-06-15 07:36:07 +02:00
2010-07-29 07:51:50 +02:00
return clientLagExceededOrWarned ;
2010-06-15 07:36:07 +02:00
}
2010-06-29 08:50:35 +02:00
bool ServerInterface : : signalClientReceiveCommands ( ConnectionSlot * connectionSlot ,
2010-06-17 23:46:36 +02:00
int slotIndex ,
bool socketTriggered ,
ConnectionSlotEvent & event ) {
2010-06-29 08:50:35 +02:00
bool slotSignalled = false ;
2010-06-17 23:46:36 +02:00
//bool socketTriggered = (connectionSlot != NULL && connectionSlot->getSocket() != NULL ? socketTriggeredList[connectionSlot->getSocket()->getSocketId()] : false);
//ConnectionSlotEvent &event = eventList[i];
event . eventType = eReceiveSocketData ;
event . networkMessage = NULL ;
event . connectionSlot = connectionSlot ;
event . socketTriggered = socketTriggered ;
event . triggerId = slotIndex ;
2010-05-15 20:59:17 +02:00
2010-06-29 08:50:35 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] slotIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , slotIndex ) ;
2010-06-17 23:46:36 +02:00
// Step #1 tell all connection slot worker threads to receive socket data
if ( connectionSlot ! = NULL ) {
2010-06-29 08:50:35 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] slotIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , slotIndex ) ;
if ( socketTriggered = = true | | connectionSlot - > isConnected ( ) = = false ) {
connectionSlot - > signalUpdate ( & event ) ;
slotSignalled = true ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] slotIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , slotIndex ) ;
}
2010-06-17 23:46:36 +02:00
}
2010-06-29 08:50:35 +02:00
return slotSignalled ;
2010-06-17 23:46:36 +02:00
}
void ServerInterface : : updateSocketTriggeredList ( std : : map < PLATFORM_SOCKET , bool > & socketTriggeredList ) {
2010-03-17 07:25:19 +01:00
//update all slots
2010-05-15 20:59:17 +02:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
2010-06-17 23:46:36 +02:00
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-03-17 07:25:19 +01:00
if ( connectionSlot ! = NULL & & connectionSlot - > getSocket ( ) ! = NULL & &
2010-06-29 08:50:35 +02:00
slots [ i ] - > getSocket ( ) - > isSocketValid ( ) = = true ) {
2010-06-17 23:46:36 +02:00
socketTriggeredList [ connectionSlot - > getSocket ( ) - > getSocketId ( ) ] = false ;
2010-03-17 07:25:19 +01:00
}
}
2010-06-17 23:46:36 +02:00
}
2010-03-17 07:25:19 +01:00
2010-08-20 22:03:06 +02:00
void ServerInterface : : validateConnectedClients ( ) {
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-08-21 20:50:56 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] Slot # %d\n",__FILE__,__FUNCTION__,__LINE__,i);
2010-08-20 22:03:06 +02:00
if ( connectionSlot ! = NULL ) {
connectionSlot - > validateConnection ( ) ;
}
}
}
2010-06-17 23:46:36 +02:00
void ServerInterface : : update ( ) {
2010-05-29 13:12:45 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-05-15 20:59:17 +02:00
2010-07-01 02:08:59 +02:00
std : : vector < string > errorMsgList ;
try {
2010-08-20 22:03:06 +02:00
// The first thing we will do is check all clients to ensure they have
// properly identified themselves within the alloted time period
validateConnectedClients ( ) ;
2010-07-01 02:08:59 +02:00
std : : map < PLATFORM_SOCKET , bool > socketTriggeredList ;
//update all slots
updateSocketTriggeredList ( socketTriggeredList ) ;
2010-05-15 20:59:17 +02:00
2010-07-01 02:08:59 +02:00
if ( gameHasBeenInitiated = = false | | socketTriggeredList . size ( ) > 0 ) {
std : : map < int , ConnectionSlotEvent > eventList ;
bool hasData = Socket : : hasDataToRead ( socketTriggeredList ) ;
2010-03-17 07:25:19 +01:00
2010-07-01 02:08:59 +02:00
if ( hasData ) SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] hasData == true \n " , __FILE__ , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
2010-07-01 02:08:59 +02:00
if ( gameHasBeenInitiated = = false | | hasData = = true ) {
std : : map < int , bool > mapSlotSignalledList ;
2010-06-29 08:50:35 +02:00
2010-07-01 02:08:59 +02:00
// Step #1 tell all connection slot worker threads to receive socket data
bool checkForNewClients = true ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-05-15 20:59:17 +02:00
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-05-15 20:59:17 +02:00
2010-07-01 02:08:59 +02:00
bool socketTriggered = ( connectionSlot ! = NULL & & connectionSlot - > getSocket ( ) ! = NULL ? socketTriggeredList [ connectionSlot - > getSocket ( ) - > getSocketId ( ) ] : false ) ;
ConnectionSlotEvent & event = eventList [ i ] ;
mapSlotSignalledList [ i ] = signalClientReceiveCommands ( connectionSlot , i , socketTriggered , event ) ;
}
2010-05-15 20:59:17 +02:00
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ============ Step #2 \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-07-01 02:08:59 +02:00
// Step #2 check all connection slot worker threads for completed status
std : : map < int , bool > slotsCompleted ;
2010-08-07 05:26:38 +02:00
for ( bool threadsDone = false ; threadsDone = = false ; ) {
threadsDone = true ;
// Examine all threads for completion of delegation
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & mapSlotSignalledList [ i ] = = true & &
slotsCompleted . find ( i ) = = slotsCompleted . end ( ) ) {
try {
std : : vector < std : : string > errorList = connectionSlot - > getThreadErrorList ( ) ;
// Collect any collected errors from threads
if ( errorList . size ( ) > 0 ) {
for ( int iErrIdx = 0 ; iErrIdx < errorList . size ( ) ; + + iErrIdx ) {
string & sErr = errorList [ iErrIdx ] ;
if ( sErr ! = " " ) {
errorMsgList . push_back ( sErr ) ;
}
}
connectionSlot - > clearThreadErrorList ( ) ;
}
connectionSlot = slots [ i ] ;
// Not done waiting for data yet
bool updateFinished = ( connectionSlot ! = NULL ? connectionSlot - > updateCompleted ( ) : true ) ;
if ( updateFinished = = false ) {
threadsDone = false ;
sleep ( 0 ) ;
break ;
}
else {
slotsCompleted [ i ] = true ;
}
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
errorMsgList . push_back ( ex . what ( ) ) ;
}
}
}
}
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ============ Step #3 \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
// Step #3 check clients for any lagging scenarios and try to deal with them
time_t waitForClientsElapsed = time ( NULL ) ;
slotsCompleted . clear ( ) ;
//std::map<int,bool> slotsWarnedAndRetried;
std : : map < int , bool > slotsWarnedList ;
2010-07-01 02:08:59 +02:00
for ( bool threadsDone = false ; threadsDone = = false ; ) {
threadsDone = true ;
// Examine all threads for completion of delegation
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-07-29 07:51:50 +02:00
if ( connectionSlot ! = NULL & & mapSlotSignalledList [ i ] = = true & &
slotsCompleted . find ( i ) = = slotsCompleted . end ( ) ) {
2010-07-01 02:08:59 +02:00
try {
std : : vector < std : : string > errorList = connectionSlot - > getThreadErrorList ( ) ;
// Show any collected errors from threads
if ( errorList . size ( ) > 0 ) {
for ( int iErrIdx = 0 ; iErrIdx < errorList . size ( ) ; + + iErrIdx ) {
string & sErr = errorList [ iErrIdx ] ;
if ( sErr ! = " " ) {
errorMsgList . push_back ( sErr ) ;
}
2010-06-30 09:03:04 +02:00
}
2010-07-01 02:08:59 +02:00
connectionSlot - > clearThreadErrorList ( ) ;
2010-06-30 09:03:04 +02:00
}
2010-05-25 20:06:42 +02:00
2010-07-02 04:50:20 +02:00
connectionSlot = slots [ i ] ;
2010-07-01 02:08:59 +02:00
// Not done waiting for data yet
2010-07-02 04:50:20 +02:00
bool updateFinished = ( connectionSlot ! = NULL ? connectionSlot - > updateCompleted ( ) : true ) ;
2010-07-01 02:08:59 +02:00
if ( updateFinished = = false ) {
threadsDone = false ;
2010-06-30 09:03:04 +02:00
sleep ( 0 ) ;
2010-07-01 02:08:59 +02:00
break ;
2010-06-30 09:03:04 +02:00
}
else {
2010-07-02 04:50:20 +02:00
connectionSlot = slots [ i ] ;
2010-07-01 02:08:59 +02:00
// New lag check
2010-07-29 07:51:50 +02:00
std : : pair < bool , bool > clientLagExceededOrWarned = std : : make_pair ( false , false ) ;
2010-07-02 04:50:20 +02:00
if ( gameHasBeenInitiated = = true & & connectionSlot ! = NULL & &
connectionSlot - > isConnected ( ) = = true ) {
2010-08-07 05:26:38 +02:00
clientLagExceededOrWarned = clientLagCheck ( connectionSlot , slotsWarnedList [ i ] ) ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , clientLagExceededOrWarned . first , clientLagExceededOrWarned . second , gameSettings . getNetworkPauseGameForLaggedClients ( ) ) ;
if ( clientLagExceededOrWarned . first = = true ) {
slotsWarnedList [ i ] = true ;
}
2010-07-01 02:08:59 +02:00
}
// If the client has exceeded lag and the server wants
// to pause while they catch up, re-trigger the
// client reader thread
2010-08-07 05:26:38 +02:00
if ( ( clientLagExceededOrWarned . first = = true & & gameSettings . getNetworkPauseGameForLaggedClients ( ) = = true ) ) { // ||
//(clientLagExceededOrWarned.second == true && slotsWarnedAndRetried[i] == false)) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, difftime(time(NULL),waitForClientsElapsed) = %.2f, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = %.2f \n " , __FILE__ , __FUNCTION__ , __LINE__ , clientLagExceededOrWarned . first , clientLagExceededOrWarned . second , difftime ( time ( NULL ) , waitForClientsElapsed ) , MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE ) ;
if ( difftime ( time ( NULL ) , waitForClientsElapsed ) < MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE ) {
connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , clientLagExceededOrWarned . first , clientLagExceededOrWarned . second ) ;
bool socketTriggered = ( connectionSlot ! = NULL & & connectionSlot - > getSocket ( ) ! = NULL ? socketTriggeredList [ connectionSlot - > getSocket ( ) - > getSocketId ( ) ] : false ) ;
ConnectionSlotEvent & event = eventList [ i ] ;
mapSlotSignalledList [ i ] = signalClientReceiveCommands ( connectionSlot , i , socketTriggered , event ) ;
sleep ( 0 ) ;
threadsDone = false ;
}
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , clientLagExceededOrWarned . first , clientLagExceededOrWarned . second ) ;
//if(gameSettings.getNetworkPauseGameForLaggedClients() == false) {
// slotsWarnedAndRetried[i] = true;
//}
2010-07-29 07:51:50 +02:00
}
2010-07-01 02:08:59 +02:00
}
else {
slotsCompleted [ i ] = true ;
}
2010-06-30 09:03:04 +02:00
}
2010-06-28 05:17:50 +02:00
}
2010-07-01 02:08:59 +02:00
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
errorMsgList . push_back ( ex . what ( ) ) ;
}
2010-06-28 05:17:50 +02:00
}
2010-07-01 02:08:59 +02:00
}
}
2010-03-17 07:25:19 +01:00
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ============ Step #4 \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-29 08:50:35 +02:00
2010-08-07 05:26:38 +02:00
// Step #4 dispatch network commands to the pending list so that they are done in proper order
2010-07-01 02:08:59 +02:00
if ( gameHasBeenInitiated = = true ) {
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = true ) {
if ( connectionSlot - > getPendingNetworkCommandList ( ) . size ( ) > 0 ) {
// New lag check
2010-08-07 05:26:38 +02:00
//std::pair<bool,bool> clientLagExceededOrWarned = clientLagCheck(connectionSlot);
//if(clientLagExceededOrWarned.first == true) {
// SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, clientLagExceeded = %d, warned = %d\n",__FILE__,__FUNCTION__,__LINE__,i,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second);
//}
//else {
2010-07-01 02:08:59 +02:00
vector < NetworkCommand > vctPendingNetworkCommandList = connectionSlot - > getPendingNetworkCommandList ( ) ;
2010-05-26 07:33:15 +02:00
2010-07-01 02:08:59 +02:00
for ( int idx = 0 ; idx < vctPendingNetworkCommandList . size ( ) ; + + idx ) {
NetworkCommand & cmd = vctPendingNetworkCommandList [ idx ] ;
this - > requestCommand ( & cmd ) ;
}
connectionSlot - > clearPendingNetworkCommandList ( ) ;
2010-08-07 05:26:38 +02:00
//}
2010-06-15 07:36:07 +02:00
}
}
2010-05-26 07:33:15 +02:00
}
}
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ============ Step #5 \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-05-15 20:59:17 +02:00
2010-08-07 05:26:38 +02:00
// Step #5 dispatch pending chat messages
2010-07-01 02:08:59 +02:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & &
connectionSlot - > getChatTextList ( ) . empty ( ) = = false ) {
try {
2010-08-07 05:26:38 +02:00
for ( int chatIdx = 0 ; slots [ i ] ! = NULL & & chatIdx < connectionSlot - > getChatTextList ( ) . size ( ) ; chatIdx + + ) {
connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL ) {
ChatMsgInfo msg ( connectionSlot - > getChatTextList ( ) [ chatIdx ] ) ;
this - > addChatInfo ( msg ) ;
2010-05-28 01:46:38 +02:00
2010-08-07 05:26:38 +02:00
string newChatText = msg . chatText . c_str ( ) ;
string newChatSender = msg . chatSender . c_str ( ) ;
int newChatTeamIndex = msg . chatTeamIndex ;
2010-05-28 01:46:38 +02:00
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
2010-05-28 01:46:38 +02:00
2010-08-07 05:26:38 +02:00
NetworkMessageText networkMessageText ( newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
broadcastMessage ( & networkMessageText , connectionSlot - > getPlayerIndex ( ) ) ;
2010-05-28 16:59:09 +02:00
2010-08-07 05:26:38 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
}
2010-07-01 02:08:59 +02:00
}
2010-07-02 04:50:20 +02:00
2010-07-02 21:57:47 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] i = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , i ) ;
2010-07-02 04:50:20 +02:00
// Its possible that the slot is disconnected here
// so check the original pointer again
if ( slots [ i ] ! = NULL ) {
2010-07-02 21:57:47 +02:00
slots [ i ] - > clearChatInfo ( ) ;
2010-07-02 04:50:20 +02:00
}
2010-07-01 02:08:59 +02:00
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
errorMsgList . push_back ( ex . what ( ) ) ;
}
2010-06-30 09:03:04 +02:00
}
2010-05-28 01:46:38 +02:00
}
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
}
}
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
errorMsgList . push_back ( ex . what ( ) ) ;
}
if ( errorMsgList . size ( ) > 0 ) {
for ( int iErrIdx = 0 ; iErrIdx < errorMsgList . size ( ) ; + + iErrIdx ) {
string & sErr = errorMsgList [ iErrIdx ] ;
if ( sErr ! = " " ) {
DisplayErrorMessage ( sErr ) ;
}
}
}
2010-05-15 20:59:17 +02:00
2010-05-29 13:12:45 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-03-17 07:25:19 +01:00
}
void ServerInterface : : updateKeyframe ( int frameCount ) {
2010-04-15 03:19:00 +02:00
Chrono chrono ;
chrono . start ( ) ;
2010-03-17 07:25:19 +01:00
2010-06-15 07:36:07 +02:00
currentFrameCount = frameCount ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] currentFrameCount = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , currentFrameCount ) ;
2010-03-17 07:25:19 +01:00
NetworkMessageCommandList networkMessageCommandList ( frameCount ) ;
//build command list, remove commands from requested and add to pending
2010-05-15 20:59:17 +02:00
while ( ! requestedCommands . empty ( ) ) {
if ( networkMessageCommandList . addCommand ( & requestedCommands . back ( ) ) ) {
2010-03-17 07:25:19 +01:00
pendingCommands . push_back ( requestedCommands . back ( ) ) ;
requestedCommands . pop_back ( ) ;
}
2010-05-15 20:59:17 +02:00
else {
2010-03-17 07:25:19 +01:00
break ;
}
}
2010-06-30 09:03:04 +02:00
try {
// Possible cause of out of synch since we have more commands that need
// to be sent in this frame
if ( ! requestedCommands . empty ( ) ) {
char szBuf [ 1024 ] = " " ;
2010-07-06 07:30:34 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , requestedCommands . size ( ) ) ;
2010-06-05 02:00:36 +02:00
2010-08-21 15:04:52 +02:00
string sMsg = " may go out of synch: server requestedCommands.size() = " + intToStr ( requestedCommands . size ( ) ) ;
2010-07-01 02:08:59 +02:00
sendTextMessage ( sMsg , - 1 , true ) ;
2010-06-30 09:03:04 +02:00
}
2010-06-05 02:00:36 +02:00
2010-07-06 07:30:34 +02:00
if ( chrono . getMillis ( ) > 0 ) SystemFlags : : OutputDebug ( SystemFlags : : debugPerformance , " In [%s::%s Line: %d] build command list took %lld msecs, networkMessageCommandList.getCommandCount() = %d, frameCount = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , chrono . getMillis ( ) , networkMessageCommandList . getCommandCount ( ) , frameCount ) ;
2010-04-15 03:19:00 +02:00
2010-06-30 09:03:04 +02:00
//broadcast commands
broadcastMessage ( & networkMessageCommandList ) ;
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-06-30 09:03:04 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
DisplayErrorMessage ( ex . what ( ) ) ;
}
2010-04-15 03:19:00 +02:00
2010-07-06 07:30:34 +02:00
if ( chrono . getMillis ( ) > 0 ) SystemFlags : : OutputDebug ( SystemFlags : : debugPerformance , " In [%s::%s Line: %d] broadcastMessage took %lld msecs, networkMessageCommandList.getCommandCount() = %d, frameCount = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , chrono . getMillis ( ) , networkMessageCommandList . getCommandCount ( ) , frameCount ) ;
2010-03-17 07:25:19 +01:00
}
2010-05-04 04:32:43 +02:00
bool ServerInterface : : shouldDiscardNetworkMessage ( NetworkMessageType networkMessageType ,
ConnectionSlot * connectionSlot ) {
bool discard = false ;
if ( connectionSlot ! = NULL ) {
switch ( networkMessageType ) {
case nmtIntro :
{
discard = true ;
NetworkMessageIntro msg = NetworkMessageIntro ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
2010-07-09 17:01:49 +02:00
case nmtPing :
{
discard = true ;
NetworkMessagePing msg = NetworkMessagePing ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
2010-07-09 19:12:57 +02:00
lastPingInfo = msg ;
2010-07-09 17:01:49 +02:00
}
break ;
2010-05-04 04:32:43 +02:00
case nmtLaunch :
{
discard = true ;
NetworkMessageLaunch msg = NetworkMessageLaunch ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtText :
{
discard = true ;
2010-07-06 07:30:34 +02:00
NetworkMessageText netMsg = NetworkMessageText ( ) ;
connectionSlot - > receiveMessage ( & netMsg ) ;
ChatMsgInfo msg ( netMsg . getText ( ) . c_str ( ) , netMsg . getSender ( ) . c_str ( ) , netMsg . getTeamIndex ( ) ) ;
this - > addChatInfo ( msg ) ;
2010-08-27 22:09:55 +02:00
string newChatText = msg . chatText . c_str ( ) ;
string newChatSender = msg . chatSender . c_str ( ) ;
int newChatTeamIndex = msg . chatTeamIndex ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
NetworkMessageText networkMessageText ( newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
broadcastMessage ( & networkMessageText , connectionSlot - > getPlayerIndex ( ) ) ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , newChatText . c_str ( ) , newChatSender . c_str ( ) , newChatTeamIndex ) ;
2010-05-04 04:32:43 +02:00
}
break ;
case nmtSynchNetworkGameData :
{
discard = true ;
NetworkMessageSynchNetworkGameData msg = NetworkMessageSynchNetworkGameData ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtSynchNetworkGameDataStatus :
{
discard = true ;
NetworkMessageSynchNetworkGameDataStatus msg = NetworkMessageSynchNetworkGameDataStatus ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtSynchNetworkGameDataFileCRCCheck :
{
discard = true ;
NetworkMessageSynchNetworkGameDataFileCRCCheck msg = NetworkMessageSynchNetworkGameDataFileCRCCheck ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtSynchNetworkGameDataFileGet :
{
discard = true ;
NetworkMessageSynchNetworkGameDataFileGet msg = NetworkMessageSynchNetworkGameDataFileGet ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtSwitchSetupRequest :
{
discard = true ;
SwitchSetupRequest msg = SwitchSetupRequest ( ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
case nmtPlayerIndexMessage :
{
discard = true ;
PlayerIndexMessage msg = PlayerIndexMessage ( 0 ) ;
connectionSlot - > receiveMessage ( & msg ) ;
}
break ;
}
}
return discard ;
}
2010-03-17 07:25:19 +01:00
void ServerInterface : : waitUntilReady ( Checksum * checksum ) {
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s] START \n " , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
Logger & logger = Logger : : getInstance ( ) ;
gameHasBeenInitiated = true ;
Chrono chrono ;
bool allReady = false ;
chrono . start ( ) ;
//wait until we get a ready message from all clients
2010-05-04 04:32:43 +02:00
while ( allReady = = false ) {
2010-03-17 07:25:19 +01:00
vector < string > waitingForHosts ;
allReady = true ;
2010-05-04 04:32:43 +02:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
2010-03-17 07:25:19 +01:00
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-05-04 04:32:43 +02:00
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = true ) {
if ( connectionSlot - > isReady ( ) = = false ) {
2010-03-17 07:25:19 +01:00
NetworkMessageType networkMessageType = connectionSlot - > getNextMessageType ( true ) ;
2010-05-04 04:32:43 +02:00
// consume old messages from the lobby
bool discarded = shouldDiscardNetworkMessage ( networkMessageType , connectionSlot ) ;
if ( discarded = = false ) {
NetworkMessageReady networkMessageReady ;
if ( networkMessageType = = nmtReady & &
connectionSlot - > receiveMessage ( & networkMessageReady ) ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s] networkMessageType==nmtReady \n " , __FUNCTION__ ) ;
connectionSlot - > setReady ( ) ;
}
else if ( networkMessageType ! = nmtInvalid ) {
//throw runtime_error("Unexpected network message: " + intToStr(networkMessageType));
string sErr = " Unexpected network message: " + intToStr ( networkMessageType ) ;
2010-07-01 02:08:59 +02:00
sendTextMessage ( sErr , - 1 , true ) ;
2010-05-04 04:32:43 +02:00
DisplayErrorMessage ( sErr ) ;
return ;
}
2010-03-17 07:25:19 +01:00
}
2010-04-30 04:34:19 +02:00
//waitingForHosts.push_back(connectionSlot->getHostName());
waitingForHosts . push_back ( connectionSlot - > getName ( ) ) ;
2010-03-17 07:25:19 +01:00
allReady = false ;
}
}
}
//check for timeout
2010-05-04 04:32:43 +02:00
if ( allReady = = false ) {
if ( chrono . getMillis ( ) > readyWaitTimeout ) {
2010-03-17 07:25:19 +01:00
//throw runtime_error("Timeout waiting for clients");
string sErr = " Timeout waiting for clients. " ;
2010-07-01 02:08:59 +02:00
sendTextMessage ( sErr , - 1 , true ) ;
2010-03-17 07:25:19 +01:00
DisplayErrorMessage ( sErr ) ;
return ;
}
2010-05-04 04:32:43 +02:00
else {
if ( chrono . getMillis ( ) % 1000 = = 0 ) {
2010-03-17 07:25:19 +01:00
string waitForHosts = " " ;
2010-05-04 04:32:43 +02:00
for ( int i = 0 ; i < waitingForHosts . size ( ) ; i + + ) {
if ( waitForHosts ! = " " ) {
2010-03-17 07:25:19 +01:00
waitForHosts + = " , " ;
}
waitForHosts + = waitingForHosts [ i ] ;
}
char szBuf [ 1024 ] = " " ;
sprintf ( szBuf , " Waiting for network: %d of %d max seconds (waiting for: %s) " , int ( chrono . getMillis ( ) / 1000 ) , int ( readyWaitTimeout / 1000 ) , waitForHosts . c_str ( ) ) ;
logger . add ( szBuf , true ) ;
}
}
}
}
// FOR TESTING ONLY - delay to see the client count up while waiting
//sleep(5000);
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s] PART B (telling client we are ready! \n " , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
2010-06-30 09:03:04 +02:00
try {
//send ready message after, so clients start delayed
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = true ) {
NetworkMessageReady networkMessageReady ( checksum - > getSum ( ) ) ;
connectionSlot - > sendMessage ( & networkMessageReady ) ;
}
2010-03-17 07:25:19 +01:00
}
2010-06-30 09:03:04 +02:00
gameStartTime = time ( NULL ) ;
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-06-30 09:03:04 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] error detected [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
DisplayErrorMessage ( ex . what ( ) ) ;
}
2010-06-28 02:21:12 +02:00
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s] END \n " , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
}
2010-07-01 02:08:59 +02:00
void ServerInterface : : sendTextMessage ( const string & text , int teamIndex , bool echoLocal ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] text [%s] teamIndex = %d, echoLocal = %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , text . c_str ( ) , teamIndex , echoLocal ) ;
2010-04-11 03:25:06 +02:00
2010-08-21 15:04:52 +02:00
NetworkMessageText networkMessageText ( text , getHumanPlayerName ( ) . c_str ( ) , teamIndex ) ;
2010-03-17 07:25:19 +01:00
broadcastMessage ( & networkMessageText ) ;
2010-04-11 03:25:06 +02:00
2010-07-01 02:08:59 +02:00
if ( echoLocal = = true ) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
ChatMsgInfo msg ( text . c_str ( ) , networkMessageText . getSender ( ) . c_str ( ) , teamIndex ) ;
2010-07-01 02:08:59 +02:00
this - > addChatInfo ( msg ) ;
}
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
}
void ServerInterface : : quitGame ( bool userManuallyQuit )
{
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-24 03:23:18 +02:00
if ( userManuallyQuit = = true ) {
//string sQuitText = Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str()) + " has chosen to leave the game!";
//NetworkMessageText networkMessageText(sQuitText,getHostName(),-1);
//broadcastMessage(&networkMessageText, -1);
2010-03-17 07:25:19 +01:00
}
NetworkMessageQuit networkMessageQuit ;
broadcastMessage ( & networkMessageQuit ) ;
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
}
2010-06-04 21:42:58 +02:00
string ServerInterface : : getNetworkStatus ( ) {
2010-03-17 07:25:19 +01:00
Lang & lang = Lang : : getInstance ( ) ;
string str ;
2010-06-04 21:42:58 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-04-11 03:25:06 +02:00
2010-03-17 07:25:19 +01:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
str + = intToStr ( i ) + " : " ;
if ( connectionSlot ! = NULL ) {
if ( connectionSlot - > isConnected ( ) ) {
2010-06-15 07:36:07 +02:00
int clientLagCount = connectionSlot - > getCurrentLagCount ( ) ;
2010-06-15 07:44:29 +02:00
double lastClientCommandListTimeLag = difftime ( time ( NULL ) , connectionSlot - > getLastReceiveCommandListTime ( ) ) ;
2010-07-02 04:50:20 +02:00
//float pingTime = connectionSlot->getThreadedPingMS(connectionSlot->getIpAddress().c_str());
2010-06-04 21:42:58 +02:00
char szBuf [ 100 ] = " " ;
2010-07-02 04:50:20 +02:00
//sprintf(szBuf,", lag = %d [%.2f], ping = %.2fms",clientLagCount,lastClientCommandListTimeLag,pingTime);
sprintf ( szBuf , " , lag = %d [%.2f] " , clientLagCount , lastClientCommandListTimeLag ) ;
2010-06-04 21:42:58 +02:00
str + = connectionSlot - > getName ( ) + string ( szBuf ) ;
2010-03-17 07:25:19 +01:00
}
}
else
{
str + = lang . get ( " NotConnected " ) ;
}
str + = ' \n ' ;
}
2010-04-11 03:25:06 +02:00
2010-06-04 21:42:58 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-04-11 03:25:06 +02:00
2010-03-17 07:25:19 +01:00
return str ;
}
bool ServerInterface : : launchGame ( const GameSettings * gameSettings ) {
bool bOkToStart = true ;
2010-08-22 10:00:05 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-04-11 03:25:06 +02:00
2010-03-17 07:25:19 +01:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i )
{
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & &
connectionSlot - > getAllowDownloadDataSynch ( ) = = true & &
connectionSlot - > isConnected ( ) )
{
if ( connectionSlot - > getNetworkGameDataSynchCheckOk ( ) = = false )
{
bOkToStart = false ;
break ;
}
}
}
if ( bOkToStart = = true )
{
2010-04-01 08:31:10 +02:00
serverSocket . stopBroadCastThread ( ) ;
2010-04-22 01:13:39 +02:00
NetworkMessageLaunch networkMessageLaunch ( gameSettings , nmtLaunch ) ;
2010-03-17 07:25:19 +01:00
broadcastMessage ( & networkMessageLaunch ) ;
}
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
return bOkToStart ;
}
2010-05-15 20:59:17 +02:00
void ServerInterface : : broadcastGameSetup ( const GameSettings * gameSettings ) {
2010-04-22 01:13:39 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-04 23:46:10 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
2010-04-22 01:13:39 +02:00
NetworkMessageLaunch networkMessageLaunch ( gameSettings , nmtBroadCastSetup ) ;
broadcastMessage ( & networkMessageLaunch ) ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
}
2010-03-17 07:25:19 +01:00
void ServerInterface : : broadcastMessage ( const NetworkMessage * networkMessage , int excludeSlot ) {
2010-05-29 13:12:45 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-03-17 07:25:19 +01:00
2010-05-29 08:56:32 +02:00
try {
2010-03-17 07:25:19 +01:00
2010-06-03 09:52:17 +02:00
if ( enabledThreadedClientCommandBroadcast = = true ) {
// Step #1 signal worker threads to send this broadcast to each client
std : : map < int , ConnectionSlotEvent > eventList ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-03-17 07:25:19 +01:00
2010-07-01 08:11:14 +02:00
// New lag check
2010-08-07 05:26:38 +02:00
//std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
//if( gameHasBeenInitiated == true && connectionSlot != NULL &&
// connectionSlot->isConnected() == true) {
// clientLagExceededOrWarned = clientLagCheck(connectionSlot);
//}
//if(clientLagExceededOrWarned.first == false) {
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] networkMessage = %p \n " , __FILE__ , __FUNCTION__ , __LINE__ , networkMessage ) ;
ConnectionSlotEvent & event = eventList [ i ] ;
event . eventType = eSendSocketData ;
event . networkMessage = networkMessage ;
event . connectionSlot = connectionSlot ;
event . socketTriggered = true ;
event . triggerId = i ;
2010-06-03 09:52:17 +02:00
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-06-03 09:52:17 +02:00
2010-07-01 08:11:14 +02:00
// Step #1 tell all connection slot worker threads to receive socket data
if ( i ! = excludeSlot & & connectionSlot ! = NULL ) {
if ( connectionSlot - > isConnected ( ) ) {
connectionSlot - > signalUpdate ( & event ) ;
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
}
else if ( gameHasBeenInitiated = = true ) {
2010-03-17 07:25:19 +01:00
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] #1 before removeSlot for slot# %d \n " , __FILE__ , __FUNCTION__ , i ) ;
removeSlot ( i ) ;
}
2010-06-03 09:52:17 +02:00
}
2010-07-01 08:11:14 +02:00
else if ( i = = excludeSlot & & gameHasBeenInitiated = = true & &
connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = false ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] #2 before removeSlot for slot# %d \n " , __FILE__ , __FUNCTION__ , i ) ;
2010-06-03 09:52:17 +02:00
removeSlot ( i ) ;
}
2010-08-07 05:26:38 +02:00
//}
2010-05-29 08:56:32 +02:00
}
2010-06-03 09:52:17 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
// Step #2 check all connection slot worker threads for completed status
std : : map < int , bool > slotsCompleted ;
for ( bool threadsDone = false ; threadsDone = = false ; ) {
threadsDone = true ;
// Examine all threads for completion of delegation
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & slotsCompleted . find ( i ) = = slotsCompleted . end ( ) ) {
std : : vector < std : : string > errorList = connectionSlot - > getThreadErrorList ( ) ;
if ( errorList . size ( ) > 0 ) {
for ( int iErrIdx = 0 ; iErrIdx < errorList . size ( ) ; + + iErrIdx ) {
string & sErr = errorList [ iErrIdx ] ;
DisplayErrorMessage ( sErr ) ;
}
connectionSlot - > clearThreadErrorList ( ) ;
}
if ( connectionSlot - > updateCompleted ( ) = = false ) {
threadsDone = false ;
break ;
}
else {
slotsCompleted [ i ] = true ;
}
}
}
sleep ( 0 ) ;
2010-03-17 07:25:19 +01:00
}
2010-06-03 09:52:17 +02:00
}
else {
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( i ! = excludeSlot & & connectionSlot ! = NULL ) {
2010-07-01 08:11:14 +02:00
// New lag check
2010-08-07 05:26:38 +02:00
//std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
//if( gameHasBeenInitiated == true && connectionSlot != NULL &&
// connectionSlot->isConnected() == true) {
// clientLagExceededOrWarned = clientLagCheck(connectionSlot);
//}
//if(clientLagExceededOrWarned.first == false) {
2010-07-01 08:11:14 +02:00
if ( connectionSlot - > isConnected ( ) ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] before sendMessage \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
connectionSlot - > sendMessage ( networkMessage ) ;
}
else if ( gameHasBeenInitiated = = true ) {
2010-06-03 09:52:17 +02:00
2010-07-01 08:11:14 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] #1 before removeSlot for slot# %d \n " , __FILE__ , __FUNCTION__ , __LINE__ , i ) ;
removeSlot ( i ) ;
}
2010-08-07 05:26:38 +02:00
//}
2010-06-03 09:52:17 +02:00
}
else if ( i = = excludeSlot & & gameHasBeenInitiated = = true & &
connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) = = false ) {
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] #2 before removeSlot for slot# %d \n " , __FILE__ , __FUNCTION__ , i ) ;
removeSlot ( i ) ;
}
}
}
2010-05-29 08:56:32 +02:00
}
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-05-29 08:56:32 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ERROR [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 02:08:59 +02:00
//throw runtime_error(ex.what());
2010-07-08 10:29:51 +02:00
//DisplayErrorMessage(ex.what());
string sMsg = ex . what ( ) ;
sendTextMessage ( sMsg , - 1 , true ) ;
2010-05-29 08:56:32 +02:00
}
2010-05-15 20:59:17 +02:00
2010-05-29 13:12:45 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
2010-03-17 07:25:19 +01:00
}
void ServerInterface : : broadcastMessageToConnectedClients ( const NetworkMessage * networkMessage , int excludeSlot ) {
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
2010-07-01 02:08:59 +02:00
try {
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
ConnectionSlot * connectionSlot = slots [ i ] ;
2010-03-17 07:25:19 +01:00
2010-07-01 02:08:59 +02:00
if ( i ! = excludeSlot & & connectionSlot ! = NULL ) {
if ( connectionSlot - > isConnected ( ) ) {
2010-03-17 07:25:19 +01:00
2010-07-01 02:08:59 +02:00
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] before sendMessage\n",__FILE__,__FUNCTION__);
connectionSlot - > sendMessage ( networkMessage ) ;
}
2010-03-17 07:25:19 +01:00
}
}
}
2010-07-01 02:08:59 +02:00
catch ( const exception & ex ) {
2010-10-06 22:22:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugError , " In [%s::%s Line: %d] Error [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
2010-07-01 02:08:59 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s Line: %d] ERROR [%s] \n " , __FILE__ , __FUNCTION__ , __LINE__ , ex . what ( ) ) ;
//throw runtime_error(ex.what());
DisplayErrorMessage ( ex . what ( ) ) ;
}
2010-03-17 07:25:19 +01:00
2010-04-11 03:25:06 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Line: %d \n " , __FILE__ , __FUNCTION__ , __LINE__ ) ;
2010-03-17 07:25:19 +01:00
}
2010-05-15 20:59:17 +02:00
void ServerInterface : : updateListen ( ) {
if ( gameHasBeenInitiated = = true ) {
return ;
}
2010-08-21 01:53:10 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
2010-03-17 07:25:19 +01:00
int openSlotCount = 0 ;
2010-05-28 07:31:17 +02:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
bool isSlotOpen = ( slots [ i ] ! = NULL & & slots [ i ] - > isConnected ( ) = = false ) ;
if ( isSlotOpen = = true ) {
2010-03-17 07:25:19 +01:00
+ + openSlotCount ;
}
}
2010-08-21 01:53:10 +02:00
//MutexSafeWrapper safeMutex(&serverSynchAccessor);
2010-03-17 07:25:19 +01:00
serverSocket . listen ( openSlotCount ) ;
2010-06-02 03:37:45 +02:00
safeMutex . ReleaseLock ( ) ;
2010-03-17 07:25:19 +01:00
}
2010-05-12 17:25:56 +02:00
int ServerInterface : : getOpenSlotCount ( ) {
int openSlotCount = 0 ;
2010-05-28 07:31:17 +02:00
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i ) {
bool isSlotOpen = ( slots [ i ] ! = NULL & & slots [ i ] - > isConnected ( ) = = false ) ;
2010-05-15 20:59:17 +02:00
2010-05-28 07:31:17 +02:00
if ( isSlotOpen = = true ) {
2010-05-12 17:25:56 +02:00
+ + openSlotCount ;
}
}
return openSlotCount ;
}
2010-08-26 21:01:44 +02:00
void ServerInterface : : setGameSettings ( GameSettings * serverGameSettings , bool waitForClientAck ) {
2010-04-29 08:10:51 +02:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] START gameSettingsUpdateCount = %d, waitForClientAck = %d \n " , __FILE__ , __FUNCTION__ , gameSettingsUpdateCount , waitForClientAck ) ;
2010-03-17 07:25:19 +01:00
2010-06-04 23:46:10 +02:00
MutexSafeWrapper safeMutex ( & serverSynchAccessor ) ;
2010-08-21 15:04:52 +02:00
gameSettings = * serverGameSettings ;
2010-03-17 07:25:19 +01:00
if ( getAllowGameDataSynchCheck ( ) = = true )
{
if ( waitForClientAck = = true & & gameSettingsUpdateCount > 0 )
{
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Waiting for client acks #1 \n " , __FILE__ , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
time_t tStart = time ( NULL ) ;
bool gotAckFromAllClients = false ;
while ( gotAckFromAllClients = = false & & difftime ( time ( NULL ) , tStart ) < = 5 )
{
gotAckFromAllClients = true ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i )
{
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) )
{
if ( connectionSlot - > getReceivedNetworkGameStatus ( ) = = false )
{
gotAckFromAllClients = false ;
}
connectionSlot - > update ( ) ;
}
}
}
}
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i )
{
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) )
{
connectionSlot - > setReceivedNetworkGameStatus ( false ) ;
}
}
NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData ( getGameSettings ( ) ) ;
broadcastMessageToConnectedClients ( & networkMessageSynchNetworkGameData ) ;
if ( waitForClientAck = = true )
{
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] Waiting for client acks #2 \n " , __FILE__ , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
time_t tStart = time ( NULL ) ;
bool gotAckFromAllClients = false ;
while ( gotAckFromAllClients = = false & & difftime ( time ( NULL ) , tStart ) < = 5 )
{
gotAckFromAllClients = true ;
for ( int i = 0 ; i < GameConstants : : maxPlayers ; + + i )
{
ConnectionSlot * connectionSlot = slots [ i ] ;
if ( connectionSlot ! = NULL & & connectionSlot - > isConnected ( ) )
{
if ( connectionSlot - > getReceivedNetworkGameStatus ( ) = = false )
{
gotAckFromAllClients = false ;
}
connectionSlot - > update ( ) ;
}
}
}
}
gameSettingsUpdateCount + + ;
}
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] END \n " , __FILE__ , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
}
void ServerInterface : : close ( )
{
2010-03-20 00:26:00 +01:00
SystemFlags : : OutputDebug ( SystemFlags : : debugNetwork , " In [%s::%s] START \n " , __FILE__ , __FUNCTION__ ) ;
2010-03-17 07:25:19 +01:00
//serverSocket = ServerSocket();
}
2010-08-21 15:04:52 +02:00
string ServerInterface : : getHumanPlayerName ( int index ) {
string result = Config : : getInstance ( ) . getString ( " NetPlayerName " , Socket : : getHostName ( ) . c_str ( ) ) ;
//printf("\nIn [%s::%s Line: %d] index = %d, gameSettings.getThisFactionIndex() = %d\n",__FILE__,__FUNCTION__,__LINE__,index,gameSettings.getThisFactionIndex());
//fflush(stdout);
if ( index > = 0 | | gameSettings . getThisFactionIndex ( ) > = 0 ) {
if ( index < 0 ) {
index = gameSettings . getThisFactionIndex ( ) ;
}
//printf("\nIn [%s::%s Line: %d] gameSettings.getNetworkPlayerName(index) = %s\n",__FILE__,__FUNCTION__,__LINE__,gameSettings.getNetworkPlayerName(index).c_str());
//fflush(stdout);
if ( gameSettings . getNetworkPlayerName ( index ) ! = " " ) {
result = gameSettings . getNetworkPlayerName ( index ) ;
}
}
return result ;
}
2010-03-17 07:25:19 +01:00
} } //end namespace