File indexing completed on 2024-04-14 03:59:24
0001 /*************************************************************************** 0002 * KBlocks, a falling blocks game by KDE * 0003 * SPDX-FileCopyrightText: 2010 Zhongjie Cai <squall.leonhart.cai@gmail.com> * 0004 * * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 ***************************************************************************/ 0007 #include "KBlocksNetServer.h" 0008 #include "GamePlayerInterface.h" 0009 #include "KBlocksDefine.h" 0010 #include "KBlocksSingleGame.h" 0011 #include "KBlocksField.h" 0012 #include "KBlocksPiece.h" 0013 0014 #include <QVarLengthArray> 0015 0016 KBlocksNetServer::KBlocksNetServer(KBlocksGameLogic *p, const QString &localIP) 0017 { 0018 mpGameLogic = p; 0019 maGameScoreList = nullptr; 0020 0021 mGameCount = 0; 0022 mGameStarted = false; 0023 mWaitForAll = false; 0024 mTopGameLevel = -1; 0025 mInitSendLength = 0; 0026 mLvUpSendLength = 0; 0027 0028 parseIPString(localIP, &mLocalAddress, &mLocalPort); 0029 // mRemoteAddress and mRemotePort are only used in recvRemoteData 0030 // and will be set there. 0031 mRemotePort = 0; 0032 0033 mpServerSocket = new QUdpSocket(this); 0034 mpServerSocket->bind(mLocalAddress, mLocalPort); 0035 0036 mRunningFlag = false; 0037 0038 mRecordFileName = string(""); 0039 mRecordFileType = true; 0040 } 0041 0042 KBlocksNetServer::~KBlocksNetServer() 0043 { 0044 delete mpServerSocket; 0045 } 0046 0047 int KBlocksNetServer::executeGame(int gameCount, bool waitForAll) 0048 { 0049 mGameCount = gameCount; 0050 mWaitForAll = waitForAll; 0051 maGameScoreList = new KBlocksScore*[mGameCount]; 0052 mTopGameLevel = -1; 0053 for (int i = 0; i < mGameCount; i++) { 0054 maGameScoreList[i] = new KBlocksScore(); 0055 maGameScoreList[i]->setLevelUpFactor(KBlocksScore_Level_x_Level_x_Factor, 1000); 0056 maGameScoreList[i]->setScoreUpFactor(10); 0057 } 0058 0059 mRunningFlag = true; 0060 0061 QList<QByteArray> tmpRecvData; 0062 QList<QString> tmpRecvAddr; 0063 int recvResult = 0; 0064 while (mRunningFlag) { 0065 recvRemoteData(&tmpRecvData, &tmpRecvAddr); 0066 0067 if (tmpRecvData.isEmpty()) { 0068 recvResult = processGame(-1); 0069 } else { 0070 recvResult = 0; 0071 for (int i = 0; i < tmpRecvData.size(); ++i) { 0072 int result = parseRemoteData(tmpRecvData[i], tmpRecvAddr[i]); 0073 if (result != -1) { 0074 processGame(result); 0075 } else { 0076 recvResult = 1; 0077 } 0078 } 0079 0080 if ((!mWaitForAll) && (recvResult == 0)) { 0081 recvResult = processGame(-1); 0082 } 0083 } 0084 0085 if ((recvResult < -1) && mGameStarted) { 0086 break; 0087 } 0088 } 0089 0090 mRunningFlag = false; 0091 0092 if (!mRecordFileName.empty()) { 0093 mpGameLogic->saveRecord(mRecordFileName.c_str(), mRecordFileType); 0094 } 0095 0096 sendGameOver(); 0097 0098 printGameResult(); 0099 0100 for (int i = 0; i < mGameCount; i++) { 0101 delete maGameScoreList[i]; 0102 } 0103 delete [] maGameScoreList; 0104 0105 if (recvResult != -2) { 0106 return 0; 0107 } 0108 0109 return recvResult; 0110 } 0111 0112 void KBlocksNetServer::setSendLength(int initLen, int lvUpLen) 0113 { 0114 mInitSendLength = initLen; 0115 mLvUpSendLength = lvUpLen; 0116 } 0117 0118 void KBlocksNetServer::setRecordFile(const char *fileName, bool binaryMode) 0119 { 0120 mRecordFileName = string(fileName); 0121 mRecordFileType = binaryMode; 0122 } 0123 0124 void KBlocksNetServer::recvRemoteData(QList<QByteArray> *recvData, QList<QString> *recvAddr) 0125 { 0126 if (!mRunningFlag) { 0127 return; 0128 } 0129 0130 recvData->clear(); 0131 recvAddr->clear(); 0132 0133 while (mpServerSocket->hasPendingDatagrams()) { 0134 QByteArray tmpData; 0135 tmpData.resize(mpServerSocket->pendingDatagramSize()); 0136 0137 mpServerSocket->readDatagram(tmpData.data(), tmpData.size(), &mRemoteAddress, &mRemotePort); 0138 QString tmpAddr = formIPString(mRemoteAddress, mRemotePort); 0139 0140 recvData->append(tmpData); 0141 recvAddr->append(tmpAddr); 0142 0143 //printf(" Recv From %s : %s\n", tmpAddr.toStdString().c_str(), tmpData.data()); 0144 //printf(" [%s:%d]\n", mRemoteAddress.toString().toStdString().c_str(), mRemotePort); 0145 } 0146 } 0147 0148 int KBlocksNetServer::processGame(int gameIndex) 0149 { 0150 if (gameIndex >= 0) { 0151 //printf("\tStepping game (%d)...\n", gameIndex); 0152 mpGameLogic->getSingleGame(gameIndex)->updateGame(); 0153 //printf("\tSending new play data (%d)...\n", gameIndex); 0154 sendPlayerData(gameIndex); 0155 return gameIndex; 0156 } else { 0157 QVarLengthArray<int, 16> removedLines(mGameCount); 0158 int activeCount = mpGameLogic->getActiveGameCount(); 0159 if ((activeCount > 1) || (mGameCount == activeCount)) { 0160 mpGameLogic->updateGame(removedLines.data()); 0161 for (int i = 0; i < mGameCount; i++) { 0162 if (maGameScoreList[i]->addScore(removedLines[i])) { 0163 int tmpLevel = maGameScoreList[i]->getGameLevel(); 0164 if (mTopGameLevel < tmpLevel) { 0165 mpGameLogic->levelUpGame(tmpLevel - mTopGameLevel); 0166 mTopGameLevel = tmpLevel; 0167 sendPlayerActionLength(); 0168 } 0169 } 0170 } 0171 if (mWaitForAll) { 0172 bool allWait = true; 0173 for (int i = 0; i < mGameCount; i++) { 0174 if (mpGameLogic->getSingleGame(i)->isActive()) { 0175 allWait = false; 0176 break; 0177 } 0178 } 0179 if (allWait) { 0180 mpGameLogic->continueGame(); 0181 } 0182 } 0183 return -1; 0184 } else { 0185 return -2; 0186 } 0187 } 0188 } 0189 0190 void KBlocksNetServer::addPlayerIP(int gameIndex, const QByteArray &data, const QString &addr) 0191 { 0192 QString playerName = QString::fromUtf8(data).mid(6); 0193 if (mPlayerMapping.find(addr) == mPlayerMapping.end()) { 0194 mPlayerIPList.append(addr); 0195 } 0196 mPlayerMapping[addr] = gameIndex; 0197 mPlayerName[gameIndex] = playerName; 0198 } 0199 0200 void KBlocksNetServer::delPlayerIP(const QString &addr) 0201 { 0202 if (mPlayerMapping.find(addr) != mPlayerMapping.end()) { 0203 mPlayerMapping.remove(addr); 0204 mPlayerIPList.removeOne(addr); 0205 } 0206 } 0207 0208 void KBlocksNetServer::sendPlayerActionLength() 0209 { 0210 QHostAddress tmpIP; 0211 quint16 tmpPort; 0212 QByteArray tmpByteData; 0213 0214 int tmpLength = mInitSendLength - mTopGameLevel * mLvUpSendLength; 0215 if (mInitSendLength <= 0) { 0216 return; 0217 } else { 0218 if (tmpLength < 1) { 0219 tmpLength = 1; 0220 } else if (tmpLength > 255) { 0221 tmpLength = 255; 0222 } 0223 } 0224 0225 QList<QString>::iterator it; 0226 for (it = mPlayerIPList.begin(); it != mPlayerIPList.end(); ++it) { 0227 parseIPString(*it, &tmpIP, &tmpPort); 0228 0229 tmpByteData.append((char) - 1); 0230 tmpByteData.append((char)tmpLength); 0231 tmpByteData.append((char)0); 0232 0233 mpServerSocket->writeDatagram(tmpByteData, tmpIP, tmpPort); 0234 } 0235 } 0236 0237 void KBlocksNetServer::sendPlayerData(int gameIndex) 0238 { 0239 char tmpData[256]; 0240 int tmpByteCount; 0241 QByteArray tmpByteData; 0242 0243 QList<QString>::iterator it; 0244 for (it = mPlayerIPList.begin(); it != mPlayerIPList.end(); ++it) { 0245 int gameID = mPlayerMapping[*it]; 0246 0247 if (gameIndex == gameID) { 0248 tmpByteData.clear(); 0249 0250 tmpByteData.append((char)gameID); 0251 0252 formByteFromInt(maGameScoreList[gameID]->getScorePoint(), tmpData + 0); 0253 formByteFromInt(maGameScoreList[gameID]->getLineCount(), tmpData + 4); 0254 formByteFromInt(maGameScoreList[gameID]->getGameLevel(), tmpData + 8); 0255 tmpByteData.append(tmpData, 12); 0256 0257 int tmpPieceCount = mpGameLogic->getSingleGame(gameID)->getPieceCount(); 0258 formByteFromInt(tmpPieceCount, tmpData); 0259 tmpByteData.append(tmpData, 4); 0260 0261 for (int i = 0; i < tmpPieceCount; ++i) { 0262 mpGameLogic->getSingleGame(gameID)->getPiece(i)->encodeData((unsigned char *)tmpData + i * 4); 0263 } 0264 tmpByteData.append(tmpData, tmpPieceCount * 4); 0265 0266 tmpByteCount = mpGameLogic->getSingleGame(gameID)->getField()->encodeData((unsigned char *)tmpData); 0267 tmpByteData.append((char)tmpByteCount); 0268 tmpByteData.append(tmpData, tmpByteCount); 0269 0270 formByteFromInt(mpGameLogic->getSingleGame(gameID)->getField()->getModifyID(), tmpData); 0271 tmpByteData.append(tmpData, 4); 0272 0273 QHostAddress tmpIP; 0274 quint16 tmpPort; 0275 parseIPString(*it, &tmpIP, &tmpPort); 0276 mpServerSocket->writeDatagram(tmpByteData, tmpIP, tmpPort); 0277 0278 //printf(" Sending data to %d @ %s\n", gameID, it->toStdString().c_str()); 0279 return; 0280 } 0281 } 0282 } 0283 0284 void KBlocksNetServer::sendGameOver() 0285 { 0286 QHostAddress tmpIP; 0287 quint16 tmpPort; 0288 QByteArray tmpByteData; 0289 0290 QList<QString>::iterator it; 0291 for (it = mPlayerIPList.begin(); it != mPlayerIPList.end(); ++it) { 0292 parseIPString(*it, &tmpIP, &tmpPort); 0293 0294 tmpByteData.append((char)127); 0295 tmpByteData.append((char) - 1); 0296 tmpByteData.append((char)0); 0297 0298 mpServerSocket->writeDatagram(tmpByteData, tmpIP, tmpPort); 0299 } 0300 } 0301 0302 void KBlocksNetServer::sendGuiData(const QString &addr) 0303 { 0304 char tmpData[256]; 0305 int tmpByteCount; 0306 QByteArray tmpByteData; 0307 0308 if (!mGameStarted) { 0309 return; 0310 } 0311 0312 QHostAddress tmpIP; 0313 quint16 tmpPort; 0314 parseIPString(addr, &tmpIP, &tmpPort); 0315 0316 for (int gameID = 0; gameID < mGameCount; ++gameID) { 0317 tmpByteData.clear(); 0318 0319 tmpByteData.append((char)gameID); 0320 0321 formByteFromInt(maGameScoreList[gameID]->getScorePoint(), tmpData + 0); 0322 formByteFromInt(maGameScoreList[gameID]->getLineCount(), tmpData + 4); 0323 formByteFromInt(maGameScoreList[gameID]->getGameLevel(), tmpData + 8); 0324 tmpByteData.append(tmpData, 12); 0325 0326 int tmpPieceCount = mpGameLogic->getSingleGame(gameID)->getPieceCount(); 0327 formByteFromInt(tmpPieceCount, tmpData); 0328 tmpByteData.append(tmpData, 4); 0329 0330 for (int i = 0; i < tmpPieceCount; ++i) { 0331 mpGameLogic->getSingleGame(gameID)->getPiece(i)->encodeData((unsigned char *)tmpData + i * 4); 0332 } 0333 tmpByteData.append(tmpData, tmpPieceCount * 4); 0334 0335 tmpByteCount = mpGameLogic->getSingleGame(gameID)->getField()->encodeData((unsigned char *)tmpData); 0336 tmpByteData.append((char)tmpByteCount); 0337 tmpByteData.append(tmpData, tmpByteCount); 0338 0339 formByteFromInt(mpGameLogic->getSingleGame(gameID)->getField()->getModifyID(), tmpData); 0340 tmpByteData.append(tmpData, 4); 0341 0342 mpServerSocket->writeDatagram(tmpByteData, tmpIP, tmpPort); 0343 } 0344 } 0345 0346 int KBlocksNetServer::parseRemoteData(const QByteArray &data, const QString &addr) 0347 { 0348 int result = -1; 0349 QString input = QString::fromLatin1(data); 0350 0351 if (input.contains(QStringLiteral("|ap|"))) { 0352 addPlayerIP((int)(data[4] - '0'), data, addr); 0353 //printf("Added player @ %s\n", input.toStdString().c_str()); 0354 } else if (input.contains(QStringLiteral("|dp|"))) { 0355 delPlayerIP(addr); 0356 //printf("Deleted player @ %s\n", input.toStdString().c_str()); 0357 } else if (input.contains(QStringLiteral("|rp|"))) { 0358 result = parsePlayerReply(data, addr); 0359 //printf("Received Player Data @ %s\n", input.toStdString().c_str()); 0360 } else if (input.contains(QStringLiteral("|rg|"))) { 0361 sendGuiData(addr); 0362 //printf("Send Gui Data @ %s\n", input.toStdString().c_str()); 0363 } else if (input.contains(QStringLiteral("|s|"))) { 0364 if (!mGameStarted) { 0365 mpGameLogic->startGame(mGameCount); 0366 mGameStarted = true; 0367 for (int i = 0; i < mGameCount; i++) { 0368 sendPlayerData(i); 0369 } 0370 //printf("Game started\n"); 0371 } 0372 } else if (input.contains(QStringLiteral("|c|"))) { 0373 if (mGameStarted) { 0374 mGameStarted = false; 0375 mpGameLogic->stopGame(); 0376 //printf("Game stopped\n"); 0377 } 0378 } else { 0379 printf("Error transmission data : %s\n", data.data()); 0380 } 0381 0382 return result; 0383 } 0384 0385 int KBlocksNetServer::parsePlayerReply(const QByteArray &data, const QString &addr) 0386 { 0387 if (!mGameStarted) { 0388 return -1; 0389 } 0390 0391 if (mPlayerMapping.find(addr) == mPlayerMapping.end()) { 0392 return -1; 0393 } 0394 0395 int gameID = mPlayerMapping[addr]; 0396 KBlocksSingleGame *mpSingleGame = mpGameLogic->getSingleGame(gameID); 0397 if (mpSingleGame == nullptr) { 0398 return -1; 0399 } 0400 0401 int counter = 4; 0402 while (data[counter] != '|') { 0403 switch (data[counter] - '0') { 0404 case PlayerAction_Move_Left: 0405 mpSingleGame->setCurrentPiece(-1, 0, 0); 0406 break; 0407 case PlayerAction_Move_Right: 0408 mpSingleGame->setCurrentPiece(1, 0, 0); 0409 break; 0410 case PlayerAction_Move_Down: 0411 mpSingleGame->setCurrentPiece(0, 1, 0); 0412 break; 0413 case PlayerAction_Push_Down: 0414 while (mpSingleGame->setCurrentPiece(0, 1, 0)) ; 0415 mpSingleGame->forceUpdateGame(); 0416 break; 0417 case PlayerAction_Rotate_CW: 0418 mpSingleGame->setCurrentPiece(0, 0, 1); 0419 break; 0420 case PlayerAction_Rotate_CCW: 0421 mpSingleGame->setCurrentPiece(0, 0, -1); 0422 break; 0423 case PlayerAction_None: 0424 default: 0425 break; 0426 } 0427 ++counter; 0428 } 0429 0430 return gameID; 0431 } 0432 0433 bool KBlocksNetServer::parseIPString(const QString &input, QHostAddress *ip, quint16 *port) 0434 { 0435 bool result = false; 0436 ip->setAddress(input.left(input.indexOf(QStringLiteral(":")))); 0437 *port = QStringView(input).mid(input.indexOf(QStringLiteral(":")) + 1).toUInt(&result); 0438 return result; 0439 } 0440 0441 QString KBlocksNetServer::formIPString(const QHostAddress &inAddr, quint16 inPort) 0442 { 0443 QString result = inAddr.toString() + QStringLiteral(":%1").arg(inPort); 0444 return result; 0445 } 0446 0447 void KBlocksNetServer::formByteFromInt(int value, char *data) 0448 { 0449 data[0] = value & 0x00FF; 0450 data[1] = (value >> 8) & 0x00FF; 0451 data[2] = (value >> 16) & 0x00FF; 0452 data[3] = (value >> 24) & 0x00FF; 0453 } 0454 0455 void KBlocksNetServer::printGameResult() 0456 { 0457 printf("-------- Game Report --------\n"); 0458 for (int gameID = 0; gameID < mGameCount; gameID++) { 0459 QString tmpPlayerName = mPlayerName[gameID]; 0460 printf("Game ID : %d\n", gameID); 0461 printf("\tPlayer Name : %s\n", tmpPlayerName.toLatin1().constData()); 0462 printf("\tTotal Score : %d\n", maGameScoreList[gameID]->getLineCount()); 0463 } 0464 printf("-----------------------------\n"); 0465 } 0466 0467 #include "moc_KBlocksNetServer.cpp"