- numerous bugfixes mostly centered around network lag, but also added more logging and protective code (like buffer overflow checks)

*NOTE: This version is NOT backwards compatible with other builds
This commit is contained in:
Mark Vejvoda
2010-08-07 03:26:38 +00:00
parent 270fa8fef0
commit fe8d3b3130
14 changed files with 373 additions and 128 deletions

View File

@@ -48,6 +48,7 @@ ClientInterface::ClientInterface(){
gotIntro = false;
lastNetworkCommandListSendTime = 0;
currentFrameCount = 0;
clientSimulationLagStartTime = 0;
networkGameDataSynchCheckOkMap = false;
networkGameDataSynchCheckOkTile = false;
@@ -508,6 +509,17 @@ void ClientInterface::updateKeyframe(int frameCount)
//wait for the next message
waitForMessage();
// START: Test simulating lag for the client
if(Config::getInstance().getInt("SimulateClientLag","0") > 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);
@@ -533,7 +545,10 @@ void ClientInterface::updateKeyframe(int frameCount)
chrono.start();
//check that we are in the right frame
if(networkMessageCommandList.getFrameCount() != frameCount) {
string sErr = "Network synchronization error, frame counts do not match, server frameCount = " + intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " + intToStr(frameCount);
string sErr = "Player: " + Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str()) +
" got a Network synchronization error, frame counts do not match, server frameCount = " +
intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " +
intToStr(frameCount);
//throw runtime_error("Network synchronization error, frame counts do not match");
sendTextMessage(sErr,-1, true);
DisplayErrorMessage(sErr);

View File

@@ -52,6 +52,7 @@ private:
int currentFrameCount;
time_t lastNetworkCommandListSendTime;
time_t clientSimulationLagStartTime;
string versionString;
public:

View File

@@ -249,11 +249,15 @@ void ConnectionSlot::update(bool checkForNewClients) {
if(socket->isConnected()) {
this->clearChatInfo();
if(socket->hasDataToRead() == true) {
NetworkMessageType networkMessageType= getNextMessageType();
bool gotTextMsg = true;
for(;socket->hasDataToRead() == true && gotTextMsg == true;) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] polling for networkMessageType...\n",__FILE__,__FUNCTION__,__LINE__);
NetworkMessageType networkMessageType= getNextMessageType(true);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType);
gotTextMsg = false;
//process incoming commands
switch(networkMessageType) {
@@ -281,6 +285,7 @@ void ConnectionSlot::update(bool checkForNewClients) {
if(receiveMessage(&networkMessageText)) {
ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getSender().c_str(),networkMessageText.getTeamIndex());
this->addChatInfo(msg);
gotTextMsg = true;
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,chatText.c_str(),chatSender.c_str(),chatTeamIndex);
}

View File

@@ -97,8 +97,9 @@ bool NetworkMessage::receive(Socket* socket, void* data, int dataSize)
return false;
}
void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const
{
void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] socket = %p, data = %p, dataSize = %d\n",__FILE__,__FUNCTION__,__LINE__,socket,data,dataSize);
if(socket != NULL) {
int sendResult = socket->send(data, dataSize);
if(sendResult != dataSize) {
@@ -137,6 +138,7 @@ bool NetworkMessageIntro::receive(Socket* socket){
}
void NetworkMessageIntro::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtIntro\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtIntro);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -163,6 +165,7 @@ bool NetworkMessagePing::receive(Socket* socket){
}
void NetworkMessagePing::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtPing\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtPing);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -185,6 +188,7 @@ bool NetworkMessageReady::receive(Socket* socket){
}
void NetworkMessageReady::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtReady\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtReady);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -258,6 +262,7 @@ bool NetworkMessageLaunch::receive(Socket* socket){
}
void NetworkMessageLaunch::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -335,6 +340,8 @@ bool NetworkMessageCommandList::receive(Socket* socket) {
}
void NetworkMessageCommandList::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtCommandList, frameCount = %d\n",__FILE__,__FUNCTION__,__LINE__,data.header.frameCount);
assert(data.header.messageType==nmtCommandList);
int totalMsgSize = commandListHeaderSize + (sizeof(NetworkCommand) * data.header.commandCount);
NetworkMessage::send(socket, &data, totalMsgSize);
@@ -359,6 +366,16 @@ void NetworkMessageCommandList::send(Socket* socket) const{
// =====================================================
NetworkMessageText::NetworkMessageText(const string &text, const string &sender, int teamIndex){
if(text.length() >= maxTextStringSize) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR - text [%s] length = %d, max = %d\n",__FILE__,__FUNCTION__,__LINE__,text.c_str(),text.length(),maxTextStringSize);
//throw runtime_error("NetworkMessageText - text.length() >= maxStringSize");
}
if(sender.length() >= maxSenderStringSize) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR - sender [%s] length = %d, max = %d\n",__FILE__,__FUNCTION__,__LINE__,sender.c_str(),sender.length(),maxSenderStringSize);
//throw runtime_error("NetworkMessageText - sender.length() >= maxSenderStringSize");
}
data.messageType= nmtText;
data.text= text;
data.sender= sender;
@@ -370,6 +387,8 @@ bool NetworkMessageText::receive(Socket* socket){
}
void NetworkMessageText::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtText\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtText);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -387,6 +406,8 @@ bool NetworkMessageQuit::receive(Socket* socket){
}
void NetworkMessageQuit::send(Socket* socket) const{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtQuit\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtQuit);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -442,8 +463,9 @@ bool NetworkMessageSynchNetworkGameData::receive(Socket* socket)
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageSynchNetworkGameData::send(Socket* socket) const
{
void NetworkMessageSynchNetworkGameData::send(Socket* socket) const {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameData\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtSynchNetworkGameData);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -467,8 +489,9 @@ bool NetworkMessageSynchNetworkGameDataStatus::receive(Socket* socket)
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageSynchNetworkGameDataStatus::send(Socket* socket) const
{
void NetworkMessageSynchNetworkGameDataStatus::send(Socket* socket) const {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataStatus\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtSynchNetworkGameDataStatus);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -492,8 +515,9 @@ bool NetworkMessageSynchNetworkGameDataFileCRCCheck::receive(Socket* socket)
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageSynchNetworkGameDataFileCRCCheck::send(Socket* socket) const
{
void NetworkMessageSynchNetworkGameDataFileCRCCheck::send(Socket* socket) const {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataFileCRCCheck\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtSynchNetworkGameDataFileCRCCheck);
NetworkMessage::send(socket, &data, sizeof(data));
}
@@ -514,8 +538,9 @@ bool NetworkMessageSynchNetworkGameDataFileGet::receive(Socket* socket)
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageSynchNetworkGameDataFileGet::send(Socket* socket) const
{
void NetworkMessageSynchNetworkGameDataFileGet::send(Socket* socket) const {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataFileGet\n",__FILE__,__FUNCTION__,__LINE__);
assert(data.messageType==nmtSynchNetworkGameDataFileGet);
NetworkMessage::send(socket, &data, sizeof(data));
}

View File

@@ -270,13 +270,14 @@ public:
class NetworkMessageText: public NetworkMessage{
private:
static const int maxStringSize= 256;
static const int maxTextStringSize= 340;
static const int maxSenderStringSize= 60;
private:
struct Data{
int8 messageType;
NetworkString<maxStringSize> text;
NetworkString<maxStringSize> sender;
NetworkString<maxTextStringSize> text;
NetworkString<maxSenderStringSize> sender;
int8 teamIndex;
};

View File

@@ -39,9 +39,13 @@ private:
char buffer[S];
public:
NetworkString() {memset(buffer, 0, S);}
void operator=(const string& str) {strncpy(buffer, str.c_str(), S-1);}
string getString() const {return buffer;}
NetworkString() {memset(buffer, 0, S);}
void operator=(const string& str) {
// ensure we don't have a buffer overflow
int maxBufferSize = sizeof(buffer) / sizeof(buffer[0]);
strncpy(buffer, str.c_str(), std::min(S-1,maxBufferSize));
}
string getString() const {return buffer;}
};
// =====================================================

View File

@@ -51,6 +51,10 @@ double warnFrameCountLagPercent = 0.65;
// Seconds grace period before we start checking LAG
double LAG_CHECK_GRACE_PERIOD = 15;
// 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;
ServerInterface::ServerInterface(){
gameHasBeenInitiated = false;
gameSettingsUpdateCount = 0;
@@ -264,7 +268,7 @@ void ServerInterface::updateSlot(ConnectionSlotEvent *event) {
}
// Only call when client has just sent us data
std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot* connectionSlot) {
std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot* connectionSlot, bool skipNetworkBroadCast) {
std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
static bool alreadyInLagCheck = false;
@@ -320,8 +324,10 @@ std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot* connectionS
#endif
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
string sMsg = szBuf;
sendTextMessage(sMsg,-1, true);
if(skipNetworkBroadCast == false) {
string sMsg = szBuf;
sendTextMessage(sMsg,-1, true);
}
if(gameSettings.getNetworkPauseGameForLaggedClients() == false) {
connectionSlot->close();
@@ -347,8 +353,10 @@ std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot* connectionS
#endif
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
string sMsg = szBuf;
sendTextMessage(sMsg,-1, true);
if(skipNetworkBroadCast == false) {
string sMsg = szBuf;
sendTextMessage(sMsg,-1, true);
}
}
}
else if(connectionSlot->getLagCountWarning() == true) {
@@ -437,11 +445,58 @@ void ServerInterface::update() {
mapSlotSignalledList[i] = signalClientReceiveCommands(connectionSlot,i,socketTriggered,event);
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #2\n",__FILE__,__FUNCTION__,__LINE__);
// Step #2 check all connection slot worker threads for completed status
std::map<int,bool> slotsCompleted;
std::map<int,bool> slotsWarnedAndRetried;
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) {
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;
for(bool threadsDone = false; threadsDone == false;) {
threadsDone = true;
// Examine all threads for completion of delegation
@@ -456,7 +511,6 @@ void ServerInterface::update() {
for(int iErrIdx = 0; iErrIdx < errorList.size(); ++iErrIdx) {
string &sErr = errorList[iErrIdx];
if(sErr != "") {
//DisplayErrorMessage(sErr);
errorMsgList.push_back(sErr);
}
}
@@ -479,20 +533,38 @@ void ServerInterface::update() {
std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
if( gameHasBeenInitiated == true && connectionSlot != NULL &&
connectionSlot->isConnected() == true) {
clientLagExceededOrWarned = clientLagCheck(connectionSlot);
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;
}
}
// If the client has exceeded lag and the server wants
// to pause while they catch up, re-trigger the
// client reader thread
if((clientLagExceededOrWarned.first == true && gameSettings.getNetworkPauseGameForLaggedClients() == true) ||
(clientLagExceededOrWarned.second == true && slotsWarnedAndRetried[i] == false)) {
bool socketTriggered = (connectionSlot != NULL && connectionSlot->getSocket() != NULL ? socketTriggeredList[connectionSlot->getSocket()->getSocketId()] : false);
ConnectionSlotEvent &event = eventList[i];
signalClientReceiveCommands(connectionSlot,i,socketTriggered,event);
sleep(0);
if((clientLagExceededOrWarned.first == true && gameSettings.getNetworkPauseGameForLaggedClients() == true)) { // ||
//(clientLagExceededOrWarned.second == true && slotsWarnedAndRetried[i] == false)) {
if(gameSettings.getNetworkPauseGameForLaggedClients() == false) {
slotsWarnedAndRetried[i] = true;
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;
//}
}
}
else {
@@ -508,20 +580,20 @@ void ServerInterface::update() {
}
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #4\n",__FILE__,__FUNCTION__,__LINE__);
// Step #3 dispatch network commands to the pending list so that they are done in proper order
// Step #4 dispatch network commands to the pending list so that they are done in proper order
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
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 {
//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 {
vector<NetworkCommand> vctPendingNetworkCommandList = connectionSlot->getPendingNetworkCommandList();
for(int idx = 0; idx < vctPendingNetworkCommandList.size(); ++idx) {
@@ -529,33 +601,36 @@ void ServerInterface::update() {
this->requestCommand(&cmd);
}
connectionSlot->clearPendingNetworkCommandList();
}
//}
}
}
}
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #5\n",__FILE__,__FUNCTION__,__LINE__);
// Step #4 dispatch pending chat messages
// Step #5 dispatch pending chat messages
for(int i= 0; i< GameConstants::maxPlayers; ++i) {
ConnectionSlot* connectionSlot= slots[i];
if(connectionSlot != NULL &&
connectionSlot->getChatTextList().empty() == false) {
try {
for(int chatIdx = 0; chatIdx < connectionSlot->getChatTextList().size(); chatIdx++) {
ChatMsgInfo msg(connectionSlot->getChatTextList()[chatIdx]);
this->addChatInfo(msg);
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);
string newChatText = msg.chatText.c_str();
string newChatSender = msg.chatSender.c_str();
int newChatTeamIndex = msg.chatTeamIndex;
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);
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());
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);
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);
}
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",__FILE__,__FUNCTION__,__LINE__,i);
@@ -573,50 +648,6 @@ void ServerInterface::update() {
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
//process text messages
/*
if(this->getChatTextList().empty() == true) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
for(int i= 0; i< GameConstants::maxPlayers; ++i) {
ConnectionSlot* connectionSlot= slots[i];
if(connectionSlot!= NULL &&
(gameHasBeenInitiated == false || (connectionSlot->getSocket() != NULL && socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true))) {
if( connectionSlot->isConnected() &&
socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true) {
if(connectionSlot->getSocket() != NULL) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] calling connectionSlot->getNextMessageType() for slots[i]->getSocket()->getSocketId() = %d\n",__FILE__,__FUNCTION__,connectionSlot->getSocket()->getSocketId());
try {
if(connectionSlot->getNextMessageType() == nmtText) {
NetworkMessageText networkMessageText;
if(connectionSlot->receiveMessage(&networkMessageText)) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 about to broadcast nmtText msg for SlotIndex# %d\n",__FILE__,__FUNCTION__,i);
broadcastMessage(&networkMessageText, i);
//chatText= networkMessageText.getText();
//chatSender= networkMessageText.getSender();
//chatTeamIndex= networkMessageText.getTeamIndex();
//break;
ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getSender().c_str(),networkMessageText.getTeamIndex());
this->addChatInfo(msg);
}
}
}
catch(const exception &ex) {
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\n",__FILE__,__FUNCTION__,__LINE__);
*/
}
}
}
@@ -990,12 +1021,12 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int
ConnectionSlot* connectionSlot = slots[i];
// New lag check
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) {
//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) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessage = %p\n",__FILE__,__FUNCTION__,__LINE__,networkMessage);
ConnectionSlotEvent &event = eventList[i];
@@ -1024,7 +1055,7 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i);
removeSlot(i);
}
}
//}
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@@ -1064,12 +1095,12 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int
if(i != excludeSlot && connectionSlot != NULL) {
// New lag check
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) {
//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) {
if(connectionSlot->isConnected()) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] before sendMessage\n",__FILE__,__FUNCTION__,__LINE__);
connectionSlot->sendMessage(networkMessage);
@@ -1079,7 +1110,7 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,__LINE__,i);
removeSlot(i);
}
}
//}
}
else if(i == excludeSlot && gameHasBeenInitiated == true &&
connectionSlot != NULL && connectionSlot->isConnected() == false) {

View File

@@ -80,7 +80,7 @@ public:
virtual void slotUpdateTask(ConnectionSlotEvent *event);
bool hasClientConnection();
int getCurrentFrameCount() const { return currentFrameCount; }
std::pair<bool,bool> clientLagCheck(ConnectionSlot* connectionSlot);
std::pair<bool,bool> clientLagCheck(ConnectionSlot* connectionSlot,bool skipNetworkBroadCast=false);
bool signalClientReceiveCommands(ConnectionSlot* connectionSlot,
int slotIndex,

View File

@@ -91,7 +91,8 @@ std::string Command::toString() const {
//SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__);
if(unitType != NULL) {
result += ", unitTypeId = " + intToStr(unitType->getId()) + ", unitTypeDesc = " + unitType->getReqDesc();
result += ", unitTypeId = " + intToStr(unitType->getId());
result += ", unitTypeDesc = " + unitType->getReqDesc();
}
//SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__);

View File

@@ -0,0 +1,117 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2008 Martio 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 "element_type.h"
#include <cassert>
#include "resource_type.h"
#include "upgrade_type.h"
#include "unit_type.h"
#include "resource.h"
#include "tech_tree.h"
#include "logger.h"
#include "lang.h"
#include "renderer.h"
#include "leak_dumper.h"
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class DisplayableType
// =====================================================
DisplayableType::DisplayableType(){
image= NULL;
}
// =====================================================
// class RequirableType
// =====================================================
string RequirableType::getReqDesc() const{
bool anyReqs= false;
string reqString="";
for(int i=0; i<getUnitReqCount(); ++i){
if(getUnitReq(i) == NULL) {
throw runtime_error("getUnitReq(i) == NULL");
}
reqString+= getUnitReq(i)->getName();
reqString+= "\n";
anyReqs= true;
}
for(int i=0; i<getUpgradeReqCount(); ++i){
if(getUpgradeReq(i) == NULL) {
throw runtime_error("getUpgradeReq(i) == NULL");
}
reqString+= getUpgradeReq(i)->getName();
reqString+= "\n";
anyReqs= true;
}
string str= getName();
if(anyReqs){
return str + " " + Lang::getInstance().get("Reqs") + ":\n" + reqString;
}
else{
return str;
}
}
// =====================================================
// class ProducibleType
// =====================================================
ProducibleType::ProducibleType(){
cancelImage= NULL;
}
ProducibleType::~ProducibleType(){
}
const Resource *ProducibleType::getCost(const ResourceType *rt) const{
for(int i=0; i<costs.size(); ++i){
if(costs[i].getType()==rt){
return &costs[i];
}
}
return NULL;
}
string ProducibleType::getReqDesc() const{
string str= getName()+" "+Lang::getInstance().get("Reqs")+":\n";
for(int i=0; i<getCostCount(); ++i){
if(getCost(i)->getAmount()!=0){
str+= getCost(i)->getType()->getName();
str+= ": "+ intToStr(getCost(i)->getAmount());
str+= "\n";
}
}
for(int i=0; i<getUnitReqCount(); ++i){
str+= getUnitReq(i)->getName();
str+= "\n";
}
for(int i=0; i<getUpgradeReqCount(); ++i){
str+= getUpgradeReq(i)->getName();
str+= "\n";
}
return str;
}
}}//end namespace

View File

@@ -155,9 +155,11 @@ void World::init(Game *game, bool createUnits){
initMap();
initSplattedTextures();
// must be done after initMap()
routePlanner = new RoutePlanner(this);
cartographer = new Cartographer(this);
// must be done after initMap()
if(gs->getPathFinderType() != pfBasic) {
routePlanner = new RoutePlanner(this);
cartographer = new Cartographer(this);
}
unitUpdater.init(game);
@@ -338,7 +340,9 @@ void World::tick(){
}
}
}
cartographer->tick();
if(cartographer != NULL) {
cartographer->tick();
}
}
Unit* World::findUnitById(int id){
@@ -784,8 +788,10 @@ void World::initUnits(){
throw runtime_error("Unit cant be placed, this error is caused because there is no enough place to put the units near its start location, make a better map: "+unit->getType()->getName() + " Faction: "+intToStr(i));
}
if (unit->getType()->hasSkillClass(scBeBuilt)) {
map.flatternTerrain(unit);
cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize());
map.flatternTerrain(unit);
if(cartographer != NULL) {
cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize());
}
}
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str());
}

View File

@@ -98,6 +98,8 @@ protected:
time_t lastThreadedPing;
Mutex pingThreadAccessor;
Mutex dataSynchAccessor;
public:
Socket(PLATFORM_SOCKET sock);
Socket();

View File

@@ -788,8 +788,14 @@ void showCursor(bool b) {
if(b) {
//SDL_GetMouseState( &x, &y );
}
int state = SDL_ShowCursor(SDL_QUERY);
if( (state == SDL_DISABLE && b == false) ||
(state == SDL_ENABLE && b == true)) {
return;
}
SDL_ShowCursor(b ? SDL_ENABLE : SDL_DISABLE);
SDL_WM_GrabInput(SDL_GRAB_OFF);
//SDL_WM_GrabInput(SDL_GRAB_OFF);
if(b) {
//SDL_WM_GrabInput(SDL_GRAB_OFF);
//SDL_WarpMouse(x,y);

View File

@@ -827,7 +827,12 @@ bool Socket::hasDataToRead(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList)
tv.tv_sec = 0;
tv.tv_usec = 0;
int retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv);
int retval = 0;
{
//MutexSafeWrapper safeMutex(&dataSynchAccessor);
retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv);
}
if(retval < 0)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d error = %s\n",__FILE__,__FUNCTION__,retval,getLastSocketErrorFormattedText().c_str());
@@ -884,7 +889,11 @@ bool Socket::hasDataToRead(PLATFORM_SOCKET socket)
tv.tv_sec = 0;
tv.tv_usec = 0;
int retval = select(socket + 1, &rfds, NULL, NULL, &tv);
int retval = 0;
{
//MutexSafeWrapper safeMutex(&dataSynchAccessor);
retval = select(socket + 1, &rfds, NULL, NULL, &tv);
}
if(retval)
{
if (FD_ISSET(socket, &rfds))
@@ -933,6 +942,10 @@ int Socket::getDataToRead(bool wantImmediateReply) {
}
else if(err == 0)
{
if(isConnected() == false) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d %s\n",__FILE__,__FUNCTION__,err,getLastSocketErrorFormattedText().c_str());
break;
}
//if(Socket::enableNetworkDebugInfo) printf("In [%s] ioctl returned = %d, size = %ld\n",__FUNCTION__,err,size);
}
@@ -962,6 +975,8 @@ int Socket::send(const void *data, int dataSize) {
ssize_t bytesSent= 0;
if(isSocketValid() == true) {
errno = 0;
MutexSafeWrapper safeMutex(&dataSynchAccessor);
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
}
@@ -985,6 +1000,7 @@ int Socket::send(const void *data, int dataSize) {
if(Socket::isWritable(true) == true) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] attemptCount = %d, sock = %d, dataSize = %d, data = %p\n",__FILE__,__FUNCTION__,__LINE__,attemptCount,sock,dataSize,data);
MutexSafeWrapper safeMutex(&dataSynchAccessor);
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during send, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesSent);
@@ -1012,6 +1028,7 @@ int Socket::receive(void *data, int dataSize)
ssize_t bytesReceived = 0;
if(isSocketValid() == true) {
MutexSafeWrapper safeMutex(&dataSynchAccessor);
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
}
if(bytesReceived < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN) {
@@ -1024,6 +1041,7 @@ int Socket::receive(void *data, int dataSize)
time_t tStartTimer = time(NULL);
while((bytesReceived < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5)) {
if(Socket::isReadable() == true) {
MutexSafeWrapper safeMutex(&dataSynchAccessor);
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during receive, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesReceived);
@@ -1044,6 +1062,7 @@ int Socket::receive(void *data, int dataSize)
int Socket::peek(void *data, int dataSize){
ssize_t err = 0;
if(isSocketValid() == true) {
MutexSafeWrapper safeMutex(&dataSynchAccessor);
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
}
if(err < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN) {
@@ -1058,6 +1077,7 @@ int Socket::peek(void *data, int dataSize){
time_t tStartTimer = time(NULL);
while((err < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5)) {
if(Socket::isReadable() == true) {
MutexSafeWrapper safeMutex(&dataSynchAccessor);
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during peek, trying again returned: %d\n",__FILE__,__FUNCTION__,err);
@@ -1106,7 +1126,11 @@ bool Socket::isReadable() {
FD_ZERO(&set);
FD_SET(sock, &set);
int i= select(sock+1, &set, NULL, NULL, &tv);
int i = 0;
{
MutexSafeWrapper safeMutex(&dataSynchAccessor);
i= select(sock+1, &set, NULL, NULL, &tv);
}
if(i < 0) {
if(difftime(time(NULL),lastDebugEvent) >= 1) {
lastDebugEvent = time(NULL);
@@ -1137,7 +1161,11 @@ bool Socket::isWritable(bool waitOnDelayedResponse) {
bool result = false;
do
{
int i = select(sock+1, NULL, &set, NULL, &tv);
int i = 0;
{
MutexSafeWrapper safeMutex(&dataSynchAccessor);
i = select(sock+1, NULL, &set, NULL, &tv);
}
if(i < 0 ) {
if(difftime(time(NULL),lastDebugEvent) >= 1) {
lastDebugEvent = time(NULL);
@@ -1302,7 +1330,10 @@ void ClientSocket::connect(const Ip &ip, int port)
FD_ZERO(&myset);
FD_SET(sock, &myset);
err = select(sock+1, NULL, &myset, NULL, &tv);
{
MutexSafeWrapper safeMutex(&dataSynchAccessor);
err = select(sock+1, NULL, &myset, NULL, &tv);
}
if (err < 0 && getLastSocketError() != PLATFORM_SOCKET_INTERRUPTED)
{