MegaGlest/source/glest_game/network/client_interface.cpp

1250 lines
56 KiB
C++
Raw Blame History

// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2008 Marti<74>o Figueroa
//
// 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 "client_interface.h"
#include <stdexcept>
#include <cassert>
#include "platform_util.h"
#include "game_util.h"
#include "conversion.h"
#include "config.h"
#include "lang.h"
#include "map.h"
#include "config.h"
#include "logger.h"
#include "window.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;
#ifdef WIN32
#define snprintf _snprintf
#endif
namespace Glest{ namespace Game{
// =====================================================
// class ClientInterface
// =====================================================
const int ClientInterface::messageWaitTimeout= 10000; //10 seconds
const int ClientInterface::waitSleepTime= 10;
const int ClientInterface::maxNetworkCommandListSendTimeWait = 4;
ClientInterface::ClientInterface() : GameNetworkInterface() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] constructor for %p\n",__FILE__,__FUNCTION__,__LINE__,this);
clientSocket= NULL;
sessionKey = 0;
launchGame= false;
introDone= false;
playerIndex= -1;
gameSettingsReceived=false;
gotIntro = false;
lastNetworkCommandListSendTime = 0;
currentFrameCount = 0;
clientSimulationLagStartTime = 0;
networkGameDataSynchCheckOkMap = false;
networkGameDataSynchCheckOkTile = false;
networkGameDataSynchCheckOkTech = false;
this->setNetworkGameDataSynchCheckTechMismatchReport("");
this->setReceivedDataSynchCheck(false);
}
ClientInterface::~ClientInterface() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] destructor for %p\n",__FILE__,__FUNCTION__,__LINE__,this);
if(clientSocket != NULL && clientSocket->isConnected() == true) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string sQuitText = "has chosen to leave the game!";
if(lang.hasString("PlayerLeftGame",languageList[i]) == true) {
sQuitText = lang.get("PlayerLeftGame",languageList[i]);
}
sendTextMessage(sQuitText,-1,false,languageList[i]);
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
delete clientSocket;
clientSocket = NULL;
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void ClientInterface::connect(const Ip &ip, int port) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START\n",__FILE__,__FUNCTION__);
delete clientSocket;
clientSocket = NULL;
this->ip = ip;
this->port = port;
clientSocket= new ClientSocket();
clientSocket->setBlock(false);
clientSocket->connect(ip, port);
connectedTime = time(NULL);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END - socket = %d\n",__FILE__,__FUNCTION__,clientSocket->getSocketId());
}
void ClientInterface::reset() {
if(getSocket() != NULL) {
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string sQuitText = "has chosen to leave the game!";
if(lang.hasString("PlayerLeftGame",languageList[i]) == true) {
sQuitText = lang.get("PlayerLeftGame",languageList[i]);
}
sendTextMessage(sQuitText,-1,false,languageList[i]);
}
close();
}
}
void ClientInterface::update() {
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
NetworkMessageCommandList networkMessageCommandList(currentFrameCount);
//send as many commands as we can
while(requestedCommands.empty() == false) {
if(networkMessageCommandList.addCommand(&requestedCommands.back())) {
requestedCommands.pop_back();
}
else {
break;
}
}
double lastSendElapsed = difftime(time(NULL),lastNetworkCommandListSendTime);
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(networkMessageCommandList.getCommandCount() > 0 ||
(lastNetworkCommandListSendTime > 0 && lastSendElapsed >= ClientInterface::maxNetworkCommandListSendTimeWait)) {
lastNetworkCommandListSendTime = time(NULL);
sendMessage(&networkMessageCommandList);
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
// Possible cause of out of synch since we have more commands that need
// to be sent in this frame
if(requestedCommands.empty() == false) {
char szBuf[4096]="";
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,requestedCommands.size());
string sMsg = "may go out of synch: client requestedCommands.size() = " + intToStr(requestedCommands.size());
sendTextMessage(sMsg,-1, true,"");
sleep(1);
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
std::string ClientInterface::getServerIpAddress() {
return this->ip.getString();
}
void ClientInterface::updateLobby() {
NetworkMessageType networkMessageType = getNextMessageType(true);
switch(networkMessageType)
{
case nmtInvalid:
break;
case nmtIntro:
{
NetworkMessageIntro networkMessageIntro;
if(receiveMessage(&networkMessageIntro)) {
gotIntro = true;
sessionKey = networkMessageIntro.getSessionId();
versionString = networkMessageIntro.getVersionString();
playerIndex= networkMessageIntro.getPlayerIndex();
serverName= networkMessageIntro.getName();
serverFTPPort = networkMessageIntro.getFtpPort();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got NetworkMessageIntro, networkMessageIntro.getGameState() = %d, versionString [%s], sessionKey = %d, playerIndex = %d, serverFTPPort = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageIntro.getGameState(),versionString.c_str(),sessionKey,playerIndex,serverFTPPort);
//check consistency
bool compatible = checkVersionComptability(networkMessageIntro.getVersionString(), getNetworkVersionSVNString());
if(compatible == false) {
//if(networkMessageIntro.getVersionString() != getNetworkVersionString()) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
bool versionMatched = false;
string platformFreeVersion = getNetworkPlatformFreeVersionString();
string sErr = "";
if(strncmp(platformFreeVersion.c_str(),networkMessageIntro.getVersionString().c_str(),strlen(platformFreeVersion.c_str())) != 0) {
string playerNameStr = getHumanPlayerName();
sErr = "Server and client binary mismatch!\nYou have to use the exactly same binaries!\n\nServer: " + networkMessageIntro.getVersionString() +
"\nClient: " + getNetworkVersionSVNString() + " player [" + playerNameStr + "]";
printf("%s\n",sErr.c_str());
sendTextMessage("Server and client binary mismatch!!",-1, true,"");
sendTextMessage(" Server:" + networkMessageIntro.getVersionString(),-1, true,"");
sendTextMessage(" Client: "+ getNetworkVersionSVNString(),-1, true,"");
sendTextMessage(" Client player [" + playerNameStr + "]",-1, true,"");
}
else {
versionMatched = true;
string playerNameStr = getHumanPlayerName();
sErr = "Warning, Server and client are using the same version but different platforms.\n\nServer: " + networkMessageIntro.getVersionString() +
"\nClient: " + getNetworkVersionSVNString() + " player [" + playerNameStr + "]";
printf("%s\n",sErr.c_str());
}
if(Config::getInstance().getBool("PlatformConsistencyChecks","true") &&
versionMatched == false) { // error message and disconnect only if checked
DisplayErrorMessage(sErr);
sleep(1);
quit= true;
close();
return;
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
if(networkMessageIntro.getGameState() == nmgstOk) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//send intro message
Lang &lang= Lang::getInstance();
NetworkMessageIntro sendNetworkMessageIntro(sessionKey,getNetworkVersionSVNString(), getHumanPlayerName(), -1, nmgstOk, this->getSocket()->getConnectedIPAddress(),serverFTPPort,lang.getLanguage());
sendMessage(&sendNetworkMessageIntro);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
if(clientSocket == NULL || clientSocket->isConnected() == false) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
string sErr = "Disconnected from server during intro handshake.";
DisplayErrorMessage(sErr);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
introDone= true;
}
}
else if(networkMessageIntro.getGameState() == nmgstNoSlots) {
string sErr = "Cannot join the server because there are no open slots for new players.";
DisplayErrorMessage(sErr);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
else {
string sErr = "Unknown response from server: " + intToStr(networkMessageIntro.getGameState());
DisplayErrorMessage(sErr);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
}
}
break;
case nmtPing:
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",__FILE__,__FUNCTION__);
NetworkMessagePing networkMessagePing;
if(receiveMessage(&networkMessagePing)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
lastPingInfo = networkMessagePing;
}
}
break;
case nmtSynchNetworkGameData:
{
NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData;
if(receiveMessage(&networkMessageSynchNetworkGameData)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got NetworkMessageSynchNetworkGameData, getTechCRCFileCount() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageSynchNetworkGameData.getTechCRCFileCount());
networkGameDataSynchCheckOkMap = false;
networkGameDataSynchCheckOkTile = false;
networkGameDataSynchCheckOkTech = false;
this->setNetworkGameDataSynchCheckTechMismatchReport("");
this->setReceivedDataSynchCheck(false);
int32 tilesetCRC = 0;
int32 techCRC = 0;
int32 mapCRC = 0;
vector<std::pair<string,int32> > vctFileList;
try {
Config &config = Config::getInstance();
string scenarioDir = "";
if(gameSettings.getScenarioDir() != "") {
scenarioDir = gameSettings.getScenarioDir();
if(EndsWith(scenarioDir, ".xml") == true) {
scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
scenarioDir = scenarioDir.erase(scenarioDir.size() - gameSettings.getScenario().size(), gameSettings.getScenario().size() + 1);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n",__FILE__,__FUNCTION__,__LINE__,gameSettings.getScenarioDir().c_str(),gameSettings.getScenario().c_str(),scenarioDir.c_str());
}
// check the checksum's
tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + networkMessageSynchNetworkGameData.getTileset() + string("/*"), ".xml", NULL);
this->setNetworkGameDataSynchCheckOkTile((tilesetCRC == networkMessageSynchNetworkGameData.getTilesetCRC()));
//if(this->getNetworkGameDataSynchCheckOkTile() == false)
//{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] tilesetCRC info, local = %d, remote = %d, networkMessageSynchNetworkGameData.getTileset() = [%s]\n",__FILE__,__FUNCTION__,__LINE__,tilesetCRC,networkMessageSynchNetworkGameData.getTilesetCRC(),networkMessageSynchNetworkGameData.getTileset().c_str());
//}
//tech, load before map because of resources
techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,scenarioDir), string("/") + networkMessageSynchNetworkGameData.getTech() + string("/*"), ".xml", NULL);
this->setNetworkGameDataSynchCheckOkTech((techCRC == networkMessageSynchNetworkGameData.getTechCRC()));
if(this->getNetworkGameDataSynchCheckOkTech() == false) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),string("/") + networkMessageSynchNetworkGameData.getTech() + "/*", ".xml", NULL);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
string report = networkMessageSynchNetworkGameData.getTechCRCFileMismatchReport(vctFileList);
this->setNetworkGameDataSynchCheckTechMismatchReport(report);
}
//if(this->getNetworkGameDataSynchCheckOkTech() == false)
//{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] techCRC info, local = %d, remote = %d, networkMessageSynchNetworkGameData.getTech() = [%s]\n",__FILE__,__FUNCTION__,techCRC,networkMessageSynchNetworkGameData.getTechCRC(),networkMessageSynchNetworkGameData.getTech().c_str());
//}
//map
Checksum checksum;
string file = Map::getMapPath(networkMessageSynchNetworkGameData.getMap(),scenarioDir, false);
if(file != "") {
checksum.addFile(file);
mapCRC = checksum.getSum();
}
this->setNetworkGameDataSynchCheckOkMap((mapCRC == networkMessageSynchNetworkGameData.getMapCRC()));
this->setReceivedDataSynchCheck(true);
//if(this->getNetworkGameDataSynchCheckOkMap() == false)
//{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] mapCRC info, local = %d, remote = %d, file = [%s]\n",__FILE__,__FUNCTION__,__LINE__,mapCRC,networkMessageSynchNetworkGameData.getMapCRC(),file.c_str());
//}
}
catch(const runtime_error &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
string sErr = ex.what();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error during processing, sErr = [%s]\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
DisplayErrorMessage(sErr);
}
NetworkMessageSynchNetworkGameDataStatus sendNetworkMessageSynchNetworkGameDataStatus(mapCRC,tilesetCRC,techCRC,vctFileList);
sendMessage(&sendNetworkMessageSynchNetworkGameDataStatus);
}
}
break;
case nmtSynchNetworkGameDataFileCRCCheck:
{
NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck))
{
Checksum checksum;
string file = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();
checksum.addFile(file);
int32 fileCRC = checksum.getSum();
if(fileCRC != networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC())
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck localCRC = %d, remoteCRC = %d, file [%s]\n",
__FILE__,__FUNCTION__,fileCRC,
networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC(),
networkMessageSynchNetworkGameDataFileCRCCheck.getFileName().c_str());
// Here we initiate a download of missing or mismatched content
NetworkMessageSynchNetworkGameDataFileGet sendNetworkMessageSynchNetworkGameDataFileGet(networkMessageSynchNetworkGameDataFileCRCCheck.getFileName());
sendMessage(&sendNetworkMessageSynchNetworkGameDataFileGet);
FileTransferInfo fileInfo;
fileInfo.hostType = eClient;
fileInfo.serverIP = this->ip.getString();
fileInfo.serverPort = this->port;
fileInfo.fileName = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();
FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
fileXferThread->start();
}
if(networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() < networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount())
{
NetworkMessageSynchNetworkGameDataFileCRCCheck sendNetworkMessageSynchNetworkGameDataFileCRCCheck(
networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount(),
networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() + 1,
0,
"");
sendMessage(&sendNetworkMessageSynchNetworkGameDataFileCRCCheck);
}
}
}
break;
case nmtText:
{
NetworkMessageText networkMessageText;
if(receiveMessage(&networkMessageText))
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtText\n",__FILE__,__FUNCTION__);
ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage());
this->addChatInfo(msg);
}
}
break;
case nmtLaunch:
case nmtBroadCastSetup:
{
NetworkMessageLaunch networkMessageLaunch;
if(receiveMessage(&networkMessageLaunch)) {
if(networkMessageLaunch.getMessageType() == nmtLaunch) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__);
}
else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",__FILE__,__FUNCTION__,__LINE__);
}
else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
char szBuf[1024]="";
snprintf(szBuf,1023,"In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
throw runtime_error(szBuf);
}
networkMessageLaunch.buildGameSettings(&gameSettings);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
//replace server player by network
for(int i= 0; i<gameSettings.getFactionCount(); ++i) {
//replace by network
if(gameSettings.getFactionControl(i)==ctHuman) {
gameSettings.setFactionControl(i, ctNetwork);
}
//set the faction index
if(gameSettings.getStartLocationIndex(i) == playerIndex) {
gameSettings.setThisFactionIndex(i);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getThisFactionIndex(i) = %d, playerIndex = %d, i = %d\n",__FILE__,__FUNCTION__,__LINE__,gameSettings.getThisFactionIndex(),playerIndex,i);
}
}
if(networkMessageLaunch.getMessageType() == nmtLaunch) {
launchGame= true;
}
else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
gameSettingsReceived=true;
}
}
}
break;
case nmtPlayerIndexMessage:
{
PlayerIndexMessage playerIndexMessage(-1);
if(receiveMessage(&playerIndexMessage)) {
playerIndex= playerIndexMessage.getPlayerIndex();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtPlayerIndexMessage, playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex);
}
}
break;
default:
{
string sErr = string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType);
//throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1, true,"");
DisplayErrorMessage(sErr);
sleep(1);
quit= true;
close();
}
}
if( clientSocket != NULL && clientSocket->isConnected() == true &&
gotIntro == false && difftime(time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] difftime(time(NULL),connectedTime) = %f\n",__FILE__,__FUNCTION__,__LINE__,difftime(time(NULL),connectedTime));
close();
}
}
void ClientInterface::updateKeyframe(int frameCount) {
currentFrameCount = frameCount;
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
int simulateLag = Config::getInstance().getInt("SimulateClientLag","0");
bool done= false;
while(done == false) {
//wait for the next message
NetworkMessageType networkMessageType = waitForMessage();
// START: Test simulating lag for the client
if(simulateLag > 0) {
if(clientSimulationLagStartTime == 0) {
clientSimulationLagStartTime = time(NULL);
}
if(difftime(time(NULL),clientSimulationLagStartTime) <= Config::getInstance().getInt("SimulateClientLagDurationSeconds","0")) {
sleep(Config::getInstance().getInt("SimulateClientLag","0"));
}
}
// END: Test simulating lag for the client
//check we have an expected message
//NetworkMessageType networkMessageType= getNextMessageType(true);
switch(networkMessageType)
{
case nmtCommandList:
{
int waitCount = 0;
//make sure we read the message
time_t receiveTimeElapsed = time(NULL);
NetworkMessageCommandList networkMessageCommandList;
bool gotCmd = receiveMessage(&networkMessageCommandList);
if(gotCmd == false) {
throw runtime_error("error retrieving nmtCommandList returned false!");
}
// while(receiveMessage(&networkMessageCommandList) == false &&
// isConnected() == true &&
// difftime(time(NULL),receiveTimeElapsed) <= (messageWaitTimeout / 2000)) {
// waitCount++;
// }
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] receiveMessage took %lld msecs, waitCount = %d\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),waitCount);
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
//check that we are in the right frame
if(networkMessageCommandList.getFrameCount() != frameCount) {
string sErr = "Player: " + getHumanPlayerName() +
" got a Network synchronization error, frame counts do not match, server frameCount = " +
intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " +
intToStr(frameCount);
sendTextMessage(sErr,-1, true,"");
DisplayErrorMessage(sErr);
sleep(1);
quit= true;
close();
return;
}
// give all commands
for(int i= 0; i < networkMessageCommandList.getCommandCount(); ++i) {
pendingCommands.push_back(*networkMessageCommandList.getCommand(i));
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] transfer network commands took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
done= true;
}
break;
case nmtPing:
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",__FILE__,__FUNCTION__);
NetworkMessagePing networkMessagePing;
if(receiveMessage(&networkMessagePing)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
lastPingInfo = networkMessagePing;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
break;
case nmtQuit:
{
time_t receiveTimeElapsed = time(NULL);
NetworkMessageQuit networkMessageQuit;
// while(receiveMessage(&networkMessageQuit) == false &&
// isConnected() == true &&
// difftime(time(NULL),receiveTimeElapsed) <= (messageWaitTimeout / 2000)) {
// }
bool gotCmd = receiveMessage(&networkMessageQuit);
if(gotCmd == false) {
throw runtime_error("error retrieving nmtQuit returned false!");
}
quit= true;
done= true;
}
break;
case nmtText:
{
time_t receiveTimeElapsed = time(NULL);
NetworkMessageText networkMessageText;
// while(receiveMessage(&networkMessageText) == false &&
// isConnected() == true &&
// difftime(time(NULL),receiveTimeElapsed) <= (messageWaitTimeout / 1000)) {
// }
bool gotCmd = receiveMessage(&networkMessageText);
if(gotCmd == false) {
throw runtime_error("error retrieving nmtText returned false!");
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage());
this->addChatInfo(msg);
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
break;
case nmtLoadingStatusMessage:
break;
case nmtInvalid:
break;
default:
{
sendTextMessage("Unexpected message in client interface: " + intToStr(networkMessageType),-1, true,"");
DisplayErrorMessage(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
sleep(1);
quit= true;
close();
done= true;
}
}
if(isConnected() == false && quit == true) {
done = true;
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
void ClientInterface::waitUntilReady(Checksum* checksum) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
Logger &logger= Logger::getInstance();
Chrono chrono;
chrono.start();
// FOR TESTING ONLY - delay to see the client count up while waiting
//sleep(5000);
//clientSocket->setBlock(true);
//send ready message
NetworkMessageReady networkMessageReady;
sendMessage(&networkMessageReady);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
NetworkMessageLoadingStatus networkMessageLoadingStatus(nmls_NONE);
Lang &lang= Lang::getInstance();
int64 lastMillisCheck = 0;
//wait until we get a ready message from the server
while(true) {
// FOR TESTING ONLY - delay to see the client count up while waiting
//sleep(2000);
if(isConnected() == false) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
string sErr = "Error, Server has disconnected!";
DisplayErrorMessage(sErr);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
NetworkMessageType networkMessageType = getNextMessageType(true);
// consume old messages from the lobby
bool discarded = shouldDiscardNetworkMessage(networkMessageType);
if(discarded == false) {
if(networkMessageType == nmtReady) {
if(receiveMessage(&networkMessageReady)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
break;
}
}
else if(networkMessageType == nmtLoadingStatusMessage) {
if(receiveMessage(&networkMessageLoadingStatus)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
}
}
else if(networkMessageType == nmtQuit) {
NetworkMessageQuit networkMessageQuit;
if(receiveMessage(&networkMessageQuit)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
DisplayErrorMessage(lang.get("GameCancelledByUser"));
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
}
else if(networkMessageType == nmtInvalid) {
if(chrono.getMillis() > readyWaitTimeout) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string sErr = "Timeout waiting for server";
if(lang.hasString("TimeoutWaitingForServer",languageList[i]) == true) {
sErr = lang.get("TimeoutWaitingForServer",languageList[i]);
}
bool echoLocal = lang.isLanguageLocal(lang.getLanguage());
sendTextMessage(sErr,-1,echoLocal,languageList[i]);
if(echoLocal) {
DisplayErrorMessage(sErr);
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
sleep(1);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
else {
if(chrono.getMillis() / 1000 > lastMillisCheck) {
lastMillisCheck = (chrono.getMillis() / 1000);
char szBuf[1024]="";
string updateTextFormat = lang.get("NetworkGameClientLoadStatus");
if(updateTextFormat == "" || updateTextFormat[0] == '?') {
updateTextFormat = "Waiting for network: %lld seconds elapsed (maximum wait time: %d seconds)";
}
string waitForHosts = "";
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER1_CONNECTED) == nmls_PLAYER1_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER1_READY) != nmls_PLAYER1_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(0);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER2_CONNECTED) == nmls_PLAYER2_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER2_READY) != nmls_PLAYER2_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(1);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER3_CONNECTED) == nmls_PLAYER3_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER3_READY) != nmls_PLAYER3_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(2);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER4_CONNECTED) == nmls_PLAYER4_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER4_READY) != nmls_PLAYER4_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(3);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER5_CONNECTED) == nmls_PLAYER5_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER5_READY) != nmls_PLAYER5_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(4);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER6_CONNECTED) == nmls_PLAYER6_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER6_READY) != nmls_PLAYER6_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(5);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER7_CONNECTED) == nmls_PLAYER7_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER7_READY) != nmls_PLAYER7_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(6);
}
}
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER8_CONNECTED) == nmls_PLAYER8_CONNECTED) {
if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER8_READY) != nmls_PLAYER8_READY) {
if(waitForHosts != "") {
waitForHosts += ", ";
}
waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(7);
}
}
sprintf(szBuf,updateTextFormat.c_str(),(long long int)lastMillisCheck,int(readyWaitTimeout / 1000));
char szBuf1[1024]="";
string statusTextFormat = lang.get("NetworkGameStatusWaiting");
if(statusTextFormat == "" || statusTextFormat[0] == '?') {
statusTextFormat = "Waiting for players: %s";
}
sprintf(szBuf1,statusTextFormat.c_str(),waitForHosts.c_str());
logger.add(szBuf, true, szBuf1);
}
}
}
else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1, true,"");
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
DisplayErrorMessage(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
sleep(1);
quit= true;
close();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
return;
}
Window::handleEvent();
// sleep a bit
sleep(waitSleepTime);
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
//check checksum
if(networkMessageReady.getChecksum() != checksum->getSum()) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string sErr = "Checksum error, you don't have the same data as the server";
if(lang.hasString("CheckSumGameLoadError",languageList[i]) == true) {
sErr = lang.get("CheckSumGameLoadError",languageList[i]);
}
bool echoLocal = lang.isLanguageLocal(lang.getLanguage());
sendTextMessage(sErr,-1,echoLocal,languageList[i]);
string playerNameStr = "Player with error is: " + getHumanPlayerName();
if(lang.hasString("CheckSumGameLoadPlayer",languageList[i]) == true) {
playerNameStr = lang.get("CheckSumGameLoadPlayer",languageList[i]) + " " + getHumanPlayerName();
}
sendTextMessage(playerNameStr,-1,echoLocal,languageList[i]);
string sErr1 = "Client Checksum: " + intToStr(checksum->getSum());
if(lang.hasString("CheckSumGameLoadClient",languageList[i]) == true) {
sErr1 = lang.get("CheckSumGameLoadClient",languageList[i]) + " " + intToStr(checksum->getSum());
}
sendTextMessage(sErr1,-1,echoLocal,languageList[i]);
string sErr2 = "Server Checksum: " + intToStr(networkMessageReady.getChecksum());
if(lang.hasString("CheckSumGameLoadServer",languageList[i]) == true) {
sErr2 = lang.get("CheckSumGameLoadServer",languageList[i]) + " " + intToStr(networkMessageReady.getChecksum());
}
sendTextMessage(sErr2,-1,echoLocal,languageList[i]);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d %s %s %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str(),sErr1.c_str(),sErr2.c_str());
if(echoLocal == true) {
if(Config::getInstance().getBool("NetworkConsistencyChecks")) {
// error message and disconnect only if checked
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
string niceError = sErr + string("\n") + sErr1 + string("\n") + sErr2;
DisplayErrorMessage(niceError);
}
}
}
// string sErr = "Checksum error, you don't have the same data as the server";
// CheckSumGameLoadError
// sendTextMessage(sErr,-1, true);
//
// string playerNameStr = "Player with error is [" + getHumanPlayerName() + "]";
// sendTextMessage(playerNameStr,-1, true);
//
// string sErr1 = "Client Checksum: " + intToStr(checksum->getSum());
// sendTextMessage(sErr1,-1, true);
//
// string sErr2 = "Server Checksum: " + intToStr(networkMessageReady.getChecksum());
// sendTextMessage(sErr2,-1, true);
// if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d %s %s %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str(),sErr1.c_str(),sErr2.c_str());
if(Config::getInstance().getBool("NetworkConsistencyChecks")) {
// error message and disconnect only if checked
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
//string niceError = sErr + string("\n") + sErr1 + string("\n") + sErr2;
//DisplayErrorMessage(niceError);
sleep(1);
quit= true;
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
close();
}
return;
}
//delay the start a bit, so clients have more room to get messages
//sleep(GameConstants::networkExtraLatency);
// This triggers LAG update packets to begin as required
lastNetworkCommandListSendTime = time(NULL);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
}
void ClientInterface::sendTextMessage(const string &text, int teamIndex, bool echoLocal,
string targetLanguage) {
string humanPlayerName = getHumanPlayerName();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] humanPlayerName = [%s] playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,humanPlayerName.c_str(),playerIndex);
NetworkMessageText networkMessageText(text, teamIndex,playerIndex,targetLanguage);
sendMessage(&networkMessageText);
if(echoLocal == true) {
ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),targetLanguage);
this->addChatInfo(msg);
}
}
void ClientInterface::sendPingMessage(int32 pingFrequency, int64 pingTime) {
NetworkMessagePing networkMessagePing(pingFrequency,pingTime);
sendMessage(&networkMessagePing);
}
string ClientInterface::getNetworkStatus() {
std::string label = Lang::getInstance().get("Server") + ": " + serverName;
//float pingTime = getThreadedPingMS(getServerIpAddress().c_str());
char szBuf[1024]="";
//sprintf(szBuf,"%s, ping = %.2fms",label.c_str(),pingTime);
sprintf(szBuf,"%s",label.c_str());
return szBuf;
}
NetworkMessageType ClientInterface::waitForMessage()
{
// Debug!
/*
sendTextMessage("Timeout waiting for message",-1);
DisplayErrorMessage("Timeout waiting for message");
quit= true;
close();
return;
*/
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
NetworkMessageType msg = nmtInvalid;
int waitLoopCount = 0;
while(msg == nmtInvalid) {
msg = getNextMessageType(true);
if(msg == nmtInvalid) {
if(chrono.getMillis() % 150 == 0 && isConnected() == false) {
if(quit == false) {
//throw runtime_error("Disconnected");
//sendTextMessage("Server has Disconnected.",-1);
DisplayErrorMessage("Server has Disconnected.");
quit= true;
}
close();
return msg;
}
if(chrono.getMillis() > messageWaitTimeout) {
//if(1) {
//throw runtime_error("Timeout waiting for message");
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string msg = "Timeout waiting for message.";
if(lang.hasString("TimeoutWaitingForMessage",languageList[i]) == true) {
msg = lang.get("TimeoutWaitingForMessage",languageList[i]);
}
sendTextMessage(msg,-1, lang.isLanguageLocal(languageList[i]),languageList[i]);
if(lang.isLanguageLocal(languageList[i]) == true) {
DisplayErrorMessage(msg);
}
}
sleep(1);
quit= true;
close();
return msg;
}
// Sleep ever second we wait to let other threads work
//else if(chrono.getMillis() % 1000 == 0) {
//sleep(0);
//}
//sleep(waitSleepTime);
}
waitLoopCount++;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] waiting took %lld msecs, waitLoopCount = %d, msg = %d\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),waitLoopCount,msg);
return msg;
}
void ClientInterface::quitGame(bool userManuallyQuit)
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] userManuallyQuit = %d\n",__FILE__,__FUNCTION__,__LINE__,userManuallyQuit);
if(clientSocket != NULL && userManuallyQuit == true)
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
for(unsigned int i = 0; i < languageList.size(); ++i) {
string msg = "has chosen to leave the game!";
if(lang.hasString("PlayerLeftGame",languageList[i]) == true) {
msg = lang.get("PlayerLeftGame",languageList[i]);
}
sendTextMessage(msg,-1, lang.isLanguageLocal(languageList[i]),languageList[i]);
}
sleep(1);
close();
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void ClientInterface::close()
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START, clientSocket = %p\n",__FILE__,__FUNCTION__,__LINE__,clientSocket);
delete clientSocket;
clientSocket= NULL;
connectedTime = 0;
gotIntro = false;
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] END\n",__FILE__,__FUNCTION__,__LINE__);
}
void ClientInterface::discoverServers(DiscoveredServersInterface *cb) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
ClientSocket::discoverServers(cb);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void ClientInterface::stopServerDiscovery() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
ClientSocket::stopBroadCastClientThread();
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void ClientInterface::sendSwitchSetupRequest(string selectedFactionName, int8 currentFactionIndex,
int8 toFactionIndex,int8 toTeam, string networkPlayerName,
int8 networkPlayerStatus, int8 flags,
string language) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkPlayerName [%s] flags = %d\n",__FILE__,__FUNCTION__,__LINE__,networkPlayerName.c_str(),flags);
SwitchSetupRequest message=SwitchSetupRequest(selectedFactionName,
currentFactionIndex, toFactionIndex,toTeam,networkPlayerName,
networkPlayerStatus, flags,language);
sendMessage(&message);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
bool ClientInterface::shouldDiscardNetworkMessage(NetworkMessageType networkMessageType) {
bool discard = false;
switch(networkMessageType) {
case nmtIntro:
{
discard = true;
NetworkMessageIntro msg = NetworkMessageIntro();
this->receiveMessage(&msg);
}
break;
case nmtPing:
{
discard = true;
NetworkMessagePing msg = NetworkMessagePing();
this->receiveMessage(&msg);
lastPingInfo = msg;
}
break;
case nmtLaunch:
{
discard = true;
NetworkMessageLaunch msg = NetworkMessageLaunch();
this->receiveMessage(&msg);
}
break;
case nmtText:
{
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtText\n",__FILE__,__FUNCTION__,__LINE__);
discard = true;
NetworkMessageText netMsg = NetworkMessageText();
this->receiveMessage(&netMsg);
ChatMsgInfo msg(netMsg.getText().c_str(),netMsg.getTeamIndex(),netMsg.getPlayerIndex(),netMsg.getTargetLanguage());
this->addChatInfo(msg);
}
break;
case nmtSynchNetworkGameData:
{
discard = true;
NetworkMessageSynchNetworkGameData msg = NetworkMessageSynchNetworkGameData();
this->receiveMessage(&msg);
}
break;
case nmtSynchNetworkGameDataStatus:
{
discard = true;
NetworkMessageSynchNetworkGameDataStatus msg = NetworkMessageSynchNetworkGameDataStatus();
this->receiveMessage(&msg);
}
break;
case nmtSynchNetworkGameDataFileCRCCheck:
{
discard = true;
NetworkMessageSynchNetworkGameDataFileCRCCheck msg = NetworkMessageSynchNetworkGameDataFileCRCCheck();
this->receiveMessage(&msg);
}
break;
case nmtSynchNetworkGameDataFileGet:
{
discard = true;
NetworkMessageSynchNetworkGameDataFileGet msg = NetworkMessageSynchNetworkGameDataFileGet();
this->receiveMessage(&msg);
}
break;
case nmtSwitchSetupRequest:
{
discard = true;
SwitchSetupRequest msg = SwitchSetupRequest();
this->receiveMessage(&msg);
}
break;
case nmtBroadCastSetup:
{
discard = true;
NetworkMessageLaunch msg = NetworkMessageLaunch();
this->receiveMessage(&msg);
}
break;
case nmtPlayerIndexMessage:
{
discard = true;
PlayerIndexMessage msg = PlayerIndexMessage(0);
this->receiveMessage(&msg);
}
break;
}
return discard;
}
string ClientInterface::getHumanPlayerName(int index) {
string result = Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str());
if(index >= 0 || gameSettings.getThisFactionIndex() >= 0) {
if(index < 0) {
index = gameSettings.getThisFactionIndex();
}
if(gameSettings.getNetworkPlayerName(index) != "") {
result = gameSettings.getNetworkPlayerName(index);
}
}
return result;
}
}}//end namespace