File indexing completed on 2024-04-21 04:02:09
0001 /****************************************************************************** 0002 * KBlocks, a falling blocks game by KDE * 0003 * SPDX-FileCopyrightText: 2009-2021 Mauricio Piacentini <mauricio@tabuleiro.com> * 0004 * Zhongjie Cai <squall.leonhart.cai@gmail.com> * 0005 * Julian Helfferich <julian.helfferich@mailbox.org> * 0006 * * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 ******************************************************************************/ 0009 #include <ctime> 0010 #include <string> 0011 #include <vector> 0012 0013 #include <KAboutData> 0014 #include <KCrash> 0015 #include <KDBusService> 0016 #include <KLocalizedString> 0017 0018 #include <KGameThemeProvider> 0019 0020 #include <QString> 0021 #include <QByteArray> 0022 #include <QApplication> 0023 #include <QCommandLineParser> 0024 #include <QCommandLineOption> 0025 0026 using namespace std; 0027 0028 #include "KBlocksConfigManager.h" 0029 0030 #include "KBlocksGameLogic.h" 0031 #include "KBlocksPlayManager.h" 0032 #include "KBlocksPlayNetwork.h" 0033 #include "KBlocksWin.h" 0034 #include "KBlocksDisplay.h" 0035 #include "KBlocksRepWin.h" 0036 0037 #include "KBlocksAppThread.h" 0038 0039 #include "AI/KBlocksAIPlayer.h" 0040 #include "KBlocksKeyboardPlayer.h" 0041 0042 #include "KBlocksNetServer.h" 0043 #include "KBlocksNetClient.h" 0044 0045 #include "kblocks_version.h" 0046 #include "settings.h" 0047 0048 KBlocksGameLogic *mpKBlocksGameLogic; 0049 KBlocksPlayManager *mpKBlocksPlayManager; 0050 KBlocksPlayNetwork *mpKBlocksPlayNetwork; 0051 KBlocksWin *mpKBlocksWindow; 0052 KBlocksDisplay *mpKBlocksDisplay; 0053 KBlocksAppThread *mpKBlocksAppThread; 0054 0055 KBlocksAIPlayer **maAIPlayers; 0056 KBlocksKeyboardPlayer **maHumanPlayers; 0057 0058 enum KBlocksGameMode { 0059 KBlocksGame_DesktopMode = 0, 0060 KBlocksGame_EngineMode, 0061 KBlocksGame_GuiMode, 0062 KBlocksGame_PlayerMode, 0063 KBlocksGame_ReplayMode, 0064 KBlocksGame_MaxMode_Count 0065 }; 0066 0067 static 0068 void initThemeProvider(KGameThemeProvider &themeProvider) 0069 { 0070 themeProvider.discoverThemes( 0071 QStringLiteral("themes"), // theme data location 0072 QStringLiteral("default")); // default theme name 0073 0074 const QByteArray themeIdentifier = Settings::theme().toUtf8(); 0075 const QList<const KGameTheme *> themes = themeProvider.themes(); 0076 for (auto* theme : themes) { 0077 if (theme->identifier() == themeIdentifier) { 0078 themeProvider.setCurrentTheme(theme); 0079 break; 0080 } 0081 } 0082 } 0083 0084 int gameDesktopMode(const QApplication &app) 0085 { 0086 // Desktop User Mode 0087 mpKBlocksGameLogic = new KBlocksGameLogic(2); 0088 mpKBlocksGameLogic->setGameSeed(std::time(nullptr)); 0089 mpKBlocksGameLogic->setGamePunish(true); 0090 mpKBlocksGameLogic->setGameStandbyMode(true); 0091 mpKBlocksGameLogic->setInitInterval(500); 0092 mpKBlocksGameLogic->setLevelUpInterval(25); 0093 0094 mpKBlocksPlayManager = new KBlocksPlayManager(mpKBlocksGameLogic, 2); 0095 0096 KGameThemeProvider themeProvider{QByteArray()}; // empty config key to disable internal config 0097 initThemeProvider(themeProvider); 0098 0099 KBlocksGraphics graphics(themeProvider.currentTheme()); 0100 KBlocksSound sound(themeProvider.currentTheme()); 0101 0102 mpKBlocksWindow = new KBlocksWin( 0103 mpKBlocksGameLogic, 0104 &graphics, 0105 &sound, 0106 &themeProvider, 0107 mpKBlocksPlayManager, 0108 2, 0109 1 0110 ); 0111 0112 mpKBlocksWindow->setupGUILayout(); 0113 mpKBlocksWindow->setUpdateInterval(50); 0114 mpKBlocksWindow->setGamesPerLine(4); 0115 mpKBlocksWindow->setGameAnimEnabled(true); 0116 mpKBlocksWindow->setWaitForAllUpdate(true); 0117 mpKBlocksWindow->show(); 0118 0119 return app.exec(); 0120 } 0121 0122 int gameEngineMode(KBlocksConfigManager *config) 0123 { 0124 int gameCount; 0125 bool sameSeq; 0126 bool hasAttack; 0127 bool standbyMode; 0128 bool hasHuman; 0129 bool sendLimit; 0130 string serverIP; 0131 0132 string recordFile; 0133 string recordType; 0134 bool recordBinary; 0135 0136 config->GetKeyInt("Engine", "GameCount", &gameCount, 1); 0137 config->GetKeyBool("Engine", "SameSequence", &sameSeq, true); 0138 config->GetKeyBool("Engine", "HasAttack", &hasAttack, true); 0139 config->GetKeyBool("Engine", "Synchronized", &standbyMode, false); 0140 config->GetKeyBool("Engine", "HasHuman", &hasHuman, false); 0141 config->GetKeyBool("Engine", "SendLimit", &sendLimit, false); 0142 config->GetKeyString("Engine", "ServerIP", &serverIP, "127.0.0.1:10086"); 0143 0144 config->GetKeyString("RecordReplay", "Record", &recordFile, ""); 0145 config->GetKeyString("RecordReplay", "Type", &recordType, "binary"); 0146 recordBinary = recordType.find("text") != 0; 0147 0148 printf("Creating game engine...\n"); 0149 printf("\tGame Count = %d\n", gameCount); 0150 printf("\tSame Sequence = %s\n", sameSeq ? "true" : "false"); 0151 printf("\tHas Attack = %s\n", hasAttack ? "true" : "false"); 0152 printf("\tSynchronized = %s\n", standbyMode ? "true" : "false"); 0153 printf("\tHas Human = %s\n", hasHuman ? "true" : "false"); 0154 printf("\tSpeed Limit = %s\n", sendLimit ? "true" : "false"); 0155 mpKBlocksGameLogic = new KBlocksGameLogic(gameCount, true); 0156 mpKBlocksGameLogic->setGameSeed(sameSeq ? std::time(nullptr) : -std::time(nullptr)); 0157 mpKBlocksGameLogic->setGamePunish(hasAttack); 0158 mpKBlocksGameLogic->setGameStandbyMode(standbyMode); 0159 mpKBlocksGameLogic->setInitInterval(hasHuman ? 500 : 0); 0160 mpKBlocksGameLogic->setLevelUpInterval(hasHuman ? 25 : 0); 0161 printf("Done...\n"); 0162 0163 printf("Creating network server...\n"); 0164 printf("\tServer IP = %s\n", serverIP.c_str()); 0165 printf("\tRecord File = %s\n", recordFile.c_str()); 0166 printf("\tRecord Type = %s\n", recordBinary ? "Binary" : "Text"); 0167 KBlocksNetServer *mpKBlocksServer = new KBlocksNetServer(mpKBlocksGameLogic, QString::fromStdString(serverIP)); 0168 mpKBlocksServer->setSendLength(sendLimit ? 10 : 0, sendLimit ? 1 : 0); 0169 mpKBlocksServer->setRecordFile(recordFile.c_str(), recordBinary); 0170 printf("Done...\n"); 0171 0172 printf("Executing game engine and network server...\n"); 0173 return mpKBlocksServer->executeGame(gameCount, standbyMode); 0174 } 0175 0176 int gameGuiMode(KBlocksConfigManager *config, const QApplication &app) 0177 { 0178 int gameCount; 0179 int gamesPerLine; 0180 int updateInterval; 0181 int localPort; 0182 string serverIP; 0183 0184 config->GetKeyInt("Gui", "GameCount", &gameCount, 1); 0185 config->GetKeyInt("Gui", "GamesPerLine", &gamesPerLine, 4); 0186 config->GetKeyInt("Gui", "UpdateInterval", &updateInterval, 1000); 0187 config->GetKeyInt("Gui", "LocalPort", &localPort, 10088); 0188 config->GetKeyString("Gui", "ServerIP", &serverIP, "127.0.0.1:10086"); 0189 0190 printf("Creating game gui...\n"); 0191 printf("\tGame Count = %d\n", gameCount); 0192 printf("\tGames Per Line = %d\n", gamesPerLine); 0193 printf("\tUpdate Interval = %d\n", updateInterval); 0194 printf("\tLocal Port = %d\n", localPort); 0195 printf("\tServer IP = %s\n", serverIP.c_str()); 0196 0197 KGameThemeProvider themeProvider{QByteArray()}; // empty config key to disable internal config 0198 initThemeProvider(themeProvider); 0199 0200 KBlocksGraphics graphics(themeProvider.currentTheme()); 0201 KBlocksSound sound(themeProvider.currentTheme()); 0202 0203 mpKBlocksDisplay = new KBlocksDisplay( 0204 &graphics, 0205 &sound, 0206 gameCount, 0207 serverIP, 0208 localPort 0209 ); 0210 mpKBlocksDisplay->setGamesPerLine(gamesPerLine); 0211 mpKBlocksDisplay->setUpdateInterval(updateInterval); 0212 mpKBlocksDisplay->show(); 0213 printf("Done...\n"); 0214 0215 printf("Starting game gui...\n"); 0216 mpKBlocksDisplay->startDisplay(); 0217 printf("Done...\n"); 0218 0219 return app.exec(); 0220 } 0221 0222 int gameReplayMode(KBlocksConfigManager *config, const QApplication &app) 0223 { 0224 int gamesPerLine; 0225 int updateInterval; 0226 int stepLength; 0227 string snapshotFolder; 0228 string snapshotFile; 0229 string recordFile; 0230 string recordType; 0231 bool recordBinary; 0232 0233 config->GetKeyInt("RecordReplay", "GamesPerLine", &gamesPerLine, 4); 0234 config->GetKeyInt("RecordReplay", "UpdateInterval", &updateInterval, 100); 0235 config->GetKeyInt("RecordReplay", "StepLength", &stepLength, 100); 0236 config->GetKeyString("RecordReplay", "SnapshotFolder", &snapshotFolder, "./snapshot/"); 0237 config->GetKeyString("RecordReplay", "SnapshotFile", &snapshotFile, ""); 0238 config->GetKeyString("RecordReplay", "Record", &recordFile, ""); 0239 config->GetKeyString("RecordReplay", "Type", &recordType, "binary"); 0240 recordBinary = recordType.find("text") != 0; 0241 0242 if (recordFile.empty()) { 0243 printf("Error loading replay file: File name is empty!\n"); 0244 return -1; 0245 } 0246 0247 printf("Creating game gui...\n"); 0248 printf("\tGames Per Line = %d\n", gamesPerLine); 0249 printf("\tUpdate Interval = %d\n", updateInterval); 0250 printf("\tStep Length = %d\n", stepLength); 0251 printf("\tSnapshot Folder = %s\n", snapshotFolder.c_str()); 0252 printf("\tSnapshot File = %s\n", snapshotFile.c_str()); 0253 printf("\tRecord File = %s\n", recordFile.c_str()); 0254 printf("\tRecord Type = %s\n", recordBinary ? "Binary" : "Text"); 0255 0256 KGameThemeProvider themeProvider{QByteArray()}; // empty config key to disable internal config 0257 initThemeProvider(themeProvider); 0258 0259 KBlocksGraphics graphics(themeProvider.currentTheme()); 0260 KBlocksSound sound(themeProvider.currentTheme()); 0261 0262 KBlocksRepWin *mpKBlocksRepWin = new KBlocksRepWin( 0263 &graphics, 0264 &sound, 0265 recordFile.c_str(), 0266 recordBinary 0267 ); 0268 if (!mpKBlocksRepWin->replayLoaded()) { 0269 printf("Error loading replay file: Failed to load replay file!\n"); 0270 return -2; 0271 } 0272 mpKBlocksRepWin->setGamesPerLine(gamesPerLine); 0273 mpKBlocksRepWin->setUpdateInterval(updateInterval); 0274 mpKBlocksRepWin->setReplayStepLength(stepLength); 0275 mpKBlocksRepWin->setSnapshotFolder(QString::fromStdString(snapshotFolder)); 0276 mpKBlocksRepWin->setSnapshotFilename(QString::fromStdString(snapshotFile)); 0277 mpKBlocksRepWin->show(); 0278 printf("Done...\n"); 0279 0280 printf("Starting game gui...\n"); 0281 mpKBlocksRepWin->startReplay(); 0282 printf("Done...\n"); 0283 0284 return app.exec(); 0285 } 0286 0287 int gamePlayerMode(KBlocksConfigManager *config, const QApplication &app) 0288 { 0289 bool hasHuman = false; 0290 int playerCount; 0291 int localPort; 0292 string serverIP; 0293 0294 config->GetKeyInt("Player", "PlayerCount", &playerCount, 1); 0295 config->GetKeyInt("Player", "LocalPort", &localPort, 10090); 0296 config->GetKeyString("Player", "ServerIP", &serverIP, "127.0.0.1:10086"); 0297 0298 printf("Creating game player manager...\n"); 0299 printf("\tPlayer Count = %d\n", playerCount); 0300 printf("\tLocal Port = %d\n", localPort); 0301 printf("\tServer IP = %s\n", serverIP.c_str()); 0302 mpKBlocksPlayNetwork = new KBlocksPlayNetwork(playerCount, serverIP, localPort); 0303 printf("Done...\n"); 0304 0305 printf("Adding game players...\n"); 0306 maAIPlayers = new KBlocksAIPlayer*[playerCount]; 0307 maHumanPlayers = new KBlocksKeyboardPlayer*[playerCount]; 0308 for (int i = 0; i < playerCount; i++) { 0309 maAIPlayers[i] = nullptr; 0310 maHumanPlayers[i] = nullptr; 0311 0312 char tmpBuf[256]; 0313 sprintf(tmpBuf, "PlayerType%d", i + 1); 0314 string tmpType = string(tmpBuf); 0315 sprintf(tmpBuf, "PlayerName%d", i + 1); 0316 string tmpName = string(tmpBuf); 0317 config->GetKeyString("Player", tmpType, &tmpType, "AI"); 0318 config->GetKeyString("Player", tmpName, &tmpName, "NoName"); 0319 0320 printf("\tNew Player (%d) Type = %s\n", i, tmpType.c_str()); 0321 printf("\t Name = %s\n", tmpName.c_str()); 0322 if (tmpType.find("ai") != tmpType.npos) { 0323 maAIPlayers[i] = new KBlocksAIPlayer(tmpName); 0324 mpKBlocksPlayNetwork->addGamePlayer(maAIPlayers[i]); 0325 } else if (tmpType.find("human") != tmpType.npos) { 0326 maHumanPlayers[i] = new KBlocksKeyboardPlayer(NULL, tmpName, true); 0327 mpKBlocksPlayNetwork->addGamePlayer(maHumanPlayers[i]); 0328 hasHuman = true; 0329 } 0330 } 0331 printf("Done...\n"); 0332 0333 printf("Starting play manager...\n"); 0334 mpKBlocksPlayNetwork->startGame(); 0335 0336 int ret = 0; 0337 if (hasHuman) { 0338 mpKBlocksAppThread = new KBlocksAppThread(mpKBlocksPlayNetwork); 0339 printf("Executing play manager...\n"); 0340 mpKBlocksAppThread->start(); 0341 0342 printf("Executing keyboard window...\n"); 0343 ret = app.exec(); 0344 0345 printf("Terminating play manager execution...\n"); 0346 mpKBlocksPlayNetwork->cancelExecute(); 0347 } else { 0348 printf("Executing...\n"); 0349 ret = mpKBlocksPlayNetwork->execute(); 0350 } 0351 0352 printf("Stopping play manager...\n"); 0353 mpKBlocksPlayNetwork->stopGame(); 0354 0355 printf("Clearing game players...\n"); 0356 mpKBlocksPlayNetwork->clearGamePlayer(); 0357 0358 printf("Exit program...\n"); 0359 return ret; 0360 } 0361 0362 int main(int argc, char *argv[]) 0363 { 0364 QApplication app(argc, argv); 0365 0366 #ifdef Q_OS_WINDOWS 0367 QApplication::setStyle(QStringLiteral("Breeze")); 0368 #endif 0369 0370 KLocalizedString::setApplicationDomain(QByteArrayLiteral("kblocks")); 0371 0372 // Game abouts... 0373 0374 KAboutData aboutData(QStringLiteral("kblocks"), 0375 i18n("KBlocks"), 0376 QStringLiteral(KBLOCKS_VERSION_STRING), 0377 i18n("A falling blocks game by KDE"), 0378 KAboutLicense::GPL, 0379 i18n("(c) 2007, Mauricio Piacentini"), 0380 QString(), 0381 QStringLiteral("https://apps.kde.org/kblocks")); 0382 aboutData.addAuthor(i18n("Mauricio Piacentini"), i18n("Author"), QStringLiteral("piacentini@kde.org")); 0383 aboutData.addAuthor(i18n("Dirk Leifeld"), i18n("Developer"), QStringLiteral("dirkleifeld@yahoo.de")); 0384 aboutData.addAuthor(i18n("Zhongjie Cai"), i18n("New design of KBlocks for AI and tetris research platform"), QStringLiteral("squall.leonhart.cai@gmail.com")); 0385 aboutData.addCredit(i18n("Johann Ollivier Lapeyre"), i18n("Oxygen art for KDE4"), QStringLiteral("johann.ollivierlapeyre@gmail.com")); 0386 0387 KAboutData::setApplicationData(aboutData); 0388 QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("kblocks"))); 0389 0390 KCrash::initialize(); 0391 0392 // Command line argument options 0393 QCommandLineParser parser; 0394 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mode"), i18n("Setup kblocks game running mode.\n\t0 = Desktop Mode\t1 = Game Engine Mode\n\t2 = Gui Mode\t3 = Player Mode"), QStringLiteral("game mode"), QStringLiteral("0"))); 0395 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("conf"), i18n("Setup the configuration file for tetris researcher mode. Not for desktop users."), QStringLiteral("configuration file"), QStringLiteral("default.conf"))); 0396 aboutData.setupCommandLine(&parser); 0397 parser.process(app); 0398 aboutData.processCommandLine(&parser); 0399 0400 KDBusService service; 0401 0402 // Get game mode 0403 int mGameMode = parser.value(QStringLiteral("mode")).toInt(); 0404 0405 QByteArray tmpFileArray = parser.value(QStringLiteral("conf")).toLatin1(); 0406 const char *tmpFileChar = tmpFileArray.data(); 0407 KBlocksConfigManager config; 0408 config.LoadConfigFile(string(tmpFileChar)); 0409 0410 int mResult = 0; 0411 switch (mGameMode) { 0412 case KBlocksGame_DesktopMode: 0413 mResult = gameDesktopMode(app); 0414 break; 0415 case KBlocksGame_EngineMode: 0416 mResult = gameEngineMode(&config); 0417 break; 0418 case KBlocksGame_GuiMode: 0419 mResult = gameGuiMode(&config, app); 0420 break; 0421 case KBlocksGame_PlayerMode: 0422 mResult = gamePlayerMode(&config, app); 0423 break; 0424 case KBlocksGame_ReplayMode: 0425 mResult = gameReplayMode(&config, app); 0426 break; 0427 } 0428 0429 return mResult; 0430 } 0431