From efa7cb03469115c8b47796ec3f3465e54a03bdf8 Mon Sep 17 00:00:00 2001 From: SoftCoder Date: Tue, 30 Dec 2014 12:16:35 -0800 Subject: [PATCH] - bugfix for shared team resources - added some new internal feature code to test auto updates for a future release --- source/glest_game/facilities/game_util.cpp | 35 +- source/glest_game/facilities/game_util.h | 2 + source/glest_game/menu/menu_state_root.cpp | 418 +++++++++++++++++- source/glest_game/menu/menu_state_root.h | 23 +- source/glest_game/world/world.cpp | 14 +- source/shared_lib/include/util/properties.h | 5 + source/shared_lib/include/util/util.h | 2 +- .../sources/platform/posix/miniftpclient.cpp | 16 +- source/shared_lib/sources/util/properties.cpp | 182 ++++---- source/shared_lib/sources/util/util.cpp | 62 ++- 10 files changed, 628 insertions(+), 131 deletions(-) diff --git a/source/glest_game/facilities/game_util.cpp b/source/glest_game/facilities/game_util.cpp index 238a7e4c..7f201f93 100644 --- a/source/glest_game/facilities/game_util.cpp +++ b/source/glest_game/facilities/game_util.cpp @@ -31,7 +31,7 @@ const char *mailString = " http://bugs.megaglest.org"; // !! Use minor versions !! Only major and minor version control compatibility! // typical version numbers look like this: v3.11-beta1.0 v3.12-dev v3.12.0 // don't forget to update mk/linux/mg-version.sh -const string glestVersionString = "v3.11-beta2.0"; +const string glestVersionString = "v3.11-dev"; const string lastCompatibleSaveGameVersionString = "v3.9.0"; #if defined(GITVERSION) @@ -53,7 +53,7 @@ string getCrashDumpFileName(){ return "megaglest" + glestVersionString + ".dmp"; } -string getPlatformNameString() { +string getPlatformTypeNameString() { static string platform; if(platform == "") { #if defined(WIN32) @@ -95,27 +95,42 @@ string getPlatformNameString() { #else platform = "???"; #endif + } + return platform; +} + +string getPlatformArchTypeNameString() { + static string platform; + if(platform == "") { #if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(_WIN64) - platform += "-X64"; + platform = "-X64"; #elif defined(_M_ALPHA) || defined(__alpha__) - platform += "-ALPHA"; + platform = "-ALPHA"; #elif defined(_M_IA64) || defined(__ia64__) - platform += "-IA64"; + platform = "-IA64"; #elif defined(_M_MRX000) || defined(__mips__) - platform += "-MIPS"; + platform = "-MIPS"; #elif defined(_M_PPC) || defined(__powerpc__) - platform += "-POWERPC"; + platform = "-POWERPC"; #elif defined(__sparc__) - platform += "-SPARC"; + platform = "-SPARC"; #elif defined(_M_ARM_FP) || defined(__arm__) || defined(_M_ARM) - platform += "-ARM"; + platform = "-ARM"; #endif } return platform; } +string getPlatformNameString() { + static string platform; + if(platform == "") { + platform = getPlatformTypeNameString() + getPlatformArchTypeNameString(); + } + return platform; +} + string getGITRevisionString() { return GIT_Rev; } @@ -197,7 +212,7 @@ string getAboutString1(int i) { case 0: return "MegaGlest " + glestVersionString + " (" + "Shared Library " + sharedLibVersionString + ")"; case 1: return "Built: " + string(__DATE__) + " " + GIT_Rev; case 2: return "Copyright 2001-2010 The Glest Team"; - case 3: return "Copyright 2010-2014 The MegaGlest Team"; + case 3: return "Copyright 2010-2015 The MegaGlest Team"; } return ""; } diff --git a/source/glest_game/facilities/game_util.h b/source/glest_game/facilities/game_util.h index 6c27e85b..81f0b4cc 100644 --- a/source/glest_game/facilities/game_util.h +++ b/source/glest_game/facilities/game_util.h @@ -34,6 +34,8 @@ extern const string networkVersionString; void initSpecialStrings(); string getCrashDumpFileName(); +string getPlatformTypeNameString(); +string getPlatformArchTypeNameString(); string getPlatformNameString(); string getGITRevisionString(); string getRAWGITRevisionString(); diff --git a/source/glest_game/menu/menu_state_root.cpp b/source/glest_game/menu/menu_state_root.cpp index a056e637..bf7baf2b 100644 --- a/source/glest_game/menu/menu_state_root.cpp +++ b/source/glest_game/menu/menu_state_root.cpp @@ -25,6 +25,7 @@ #include "network_message.h" #include "socket.h" #include "auto_test.h" +#include #include "leak_dumper.h" @@ -34,10 +35,16 @@ namespace Glest{ namespace Game{ // class MenuStateRoot // ===================================================== +bool MenuStateRoot::gameUpdateChecked = false; + MenuStateRoot::MenuStateRoot(Program *program, MainMenu *mainMenu): - MenuState(program, mainMenu, "root") + MenuState(program, mainMenu, "root"), updatesHttpServerThread(NULL) { containerName = "MainMenu"; + + ftpClientThread = NULL; + lastDownloadProgress = 0; + Lang &lang= Lang::getInstance(); int yPos=440; @@ -87,6 +94,10 @@ MenuStateRoot::MenuStateRoot(Program *program, MainMenu *mainMenu): errorMessageBox.init(lang.getString("Ok")); errorMessageBox.setEnabled(false); + ftpMessageBox.registerGraphicComponent(containerName,"ftpMessageBox"); + ftpMessageBox.init(lang.getString("Yes"), lang.getString("No")); + ftpMessageBox.setEnabled(false); + //PopupMenu popupMenu; std::vector menuItems; menuItems.push_back("1"); @@ -101,6 +112,57 @@ MenuStateRoot::MenuStateRoot(Program *program, MainMenu *mainMenu): GraphicComponent::applyAllCustomProperties(containerName); } +MenuStateRoot::~MenuStateRoot() { + if(updatesHttpServerThread != NULL) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + updatesHttpServerThread->setSimpleTaskInterfaceValid(false); + updatesHttpServerThread->signalQuit(); + updatesHttpServerThread->setThreadOwnerValid(false); + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + if( updatesHttpServerThread->canShutdown(true) == true && + updatesHttpServerThread->shutdownAndWait() == true) { + delete updatesHttpServerThread; + } + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + updatesHttpServerThread = NULL; + } + + if(ftpClientThread != NULL) { + ftpClientThread->setCallBackObject(NULL); + ftpClientThread->signalQuit(); + sleep(0); + if(ftpClientThread->canShutdown(true) == true && + ftpClientThread->shutdownAndWait() == true) { + delete ftpClientThread; + } + else { + char szBuf[8096]=""; + snprintf(szBuf,8096,"In [%s::%s %d] Error cannot shutdown ftpClientThread\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); + //SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s",szBuf); + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s",szBuf); + + //publishToMasterserverThread->cleanup(); + } + ftpClientThread = NULL; + +// ftpClientThread->signalQuit(); +// ftpClientThread->setCallBackObject(NULL); +// if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); +// if( ftpClientThread->shutdownAndWait() == true) { +// if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); +// delete ftpClientThread; +// } +// ftpClientThread = NULL; +// if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + +} + void MenuStateRoot::reloadUI() { Lang &lang= Lang::getInstance(); @@ -122,6 +184,8 @@ void MenuStateRoot::reloadUI() { mainMessageBox.init(lang.getString("Yes"), lang.getString("No")); errorMessageBox.init(lang.getString("Ok")); + ftpMessageBox.init(lang.getString("Yes"), lang.getString("No")); + console.resetFonts(); GraphicComponent::reloadFontsForRegisterGraphicComponents(containerName); @@ -163,6 +227,28 @@ void MenuStateRoot::mouseClick(int x, int y, MouseButton mouseButton){ errorMessageBox.setEnabled(false); } } + + else if(ftpMessageBox.getEnabled()) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + int button= 0; + if(ftpMessageBox.mouseClick(x, y, button)) { + ftpMessageBox.setEnabled(false); + if(button == 0) { + startFTPClientIfRequired(); + + lastDownloadProgress = 0; + printf("Adding ftpFileName [%s] ftpFileURL [%s]\n",ftpFileName.c_str(),ftpFileURL.c_str()); + if(ftpClientThread != NULL) ftpClientThread->addTempFileToRequests(ftpFileName,ftpFileURL); + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutexFTPProgress((ftpClientThread != NULL ? ftpClientThread->getProgressMutex() : NULL),mutexOwnerId); + if(ftpClientThread != NULL && ftpClientThread->getProgressMutex() != NULL) ftpClientThread->getProgressMutex()->setOwnerId(mutexOwnerId); + fileFTPProgressList[ftpFileName] = pair(0,""); + safeMutexFTPProgress.ReleaseLock(); + } + } + } else if(mainMessageBox.getEnabled() == false && buttonNewGame.mouseClick(x, y)){ soundRenderer.playFx(coreData.getClickSoundB()); mainMenu->setState(new MenuStateNewGame(program, mainMenu)); @@ -196,6 +282,195 @@ void MenuStateRoot::mouseClick(int x, int y, MouseButton mouseButton){ } } +void MenuStateRoot::startFTPClientIfRequired() { + if(ftpClientThread == NULL) { + // Setup File Transfer thread + Config &config = Config::getInstance(); + + vector tilesetFiles; + vector tilesetFilesUserData; + + vector techTreeFiles; + vector techTreeFilesUserData; + + + findDirs(config.getPathListForType(ptTilesets), tilesetFiles); + findDirs(config.getPathListForType(ptTechs), techTreeFiles); + + vector mapPathList = config.getPathListForType(ptMaps); + std::pair mapsPath; + if(mapPathList.empty() == false) { + mapsPath.first = mapPathList[0]; + } + if(mapPathList.size() > 1) { + mapsPath.second = mapPathList[1]; + } + std::pair tilesetsPath; + vector tilesetsList = Config::getInstance().getPathListForType(ptTilesets); + if(tilesetsList.empty() == false) { + tilesetsPath.first = tilesetsList[0]; + if(tilesetsList.size() > 1) { + tilesetsPath.second = tilesetsList[1]; + } + } + + std::pair techtreesPath; + vector techtreesList = Config::getInstance().getPathListForType(ptTechs); + if(techtreesList.empty() == false) { + techtreesPath.first = techtreesList[0]; + if(techtreesList.size() > 1) { + techtreesPath.second = techtreesList[1]; + } + } + + std::pair scenariosPath; + vector scenariosList = Config::getInstance().getPathListForType(ptScenarios); + if(scenariosList.empty() == false) { + scenariosPath.first = scenariosList[0]; + if(scenariosList.size() > 1) { + scenariosPath.second = scenariosList[1]; + } + } + + string fileArchiveExtension = config.getString("FileArchiveExtension",""); + string fileArchiveExtractCommand = config.getString("FileArchiveExtractCommand",""); + string fileArchiveExtractCommandParameters = config.getString("FileArchiveExtractCommandParameters",""); + int32 fileArchiveExtractCommandSuccessResult = config.getInt("FileArchiveExtractCommandSuccessResult","0"); + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + console.setOnlyChatMessagesInStoredLines(false); + + // Get path to temp files + string tempFilePath = "temp/"; + if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") { + tempFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + tempFilePath; + } + else { + string userData = config.getString("UserData_Root",""); + if(userData != "") { + endPathWithSlash(userData); + } + tempFilePath = userData + tempFilePath; + } + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Temp files path [%s]\n",tempFilePath.c_str()); + + ftpClientThread = new FTPClientThread(-1,"", + mapsPath,tilesetsPath,techtreesPath,scenariosPath, + this,fileArchiveExtension,fileArchiveExtractCommand, + fileArchiveExtractCommandParameters, + fileArchiveExtractCommandSuccessResult, + tempFilePath); + ftpClientThread->start(); + + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + } +} + +void MenuStateRoot::FTPClient_CallbackEvent(string itemName, + FTP_Client_CallbackType type, pair result,void *userdata) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + Lang &lang= Lang::getInstance(); + if(type == ftp_cct_DownloadProgress) { + FTPClientCallbackInterface::FtpProgressStats *stats = (FTPClientCallbackInterface::FtpProgressStats *)userdata; + if(stats != NULL) { + int fileProgress = 0; + if(stats->download_total > 0) { + fileProgress = ((stats->download_now / stats->download_total) * 100.0); + } + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Got FTP Callback for [%s] current file [%s] fileProgress = %d [now = %f, total = %f]\n",itemName.c_str(),stats->currentFilename.c_str(), fileProgress,stats->download_now,stats->download_total); + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutexFTPProgress((ftpClientThread != NULL ? ftpClientThread->getProgressMutex() : NULL),mutexOwnerId); + if(ftpClientThread != NULL && ftpClientThread->getProgressMutex() != NULL) ftpClientThread->getProgressMutex()->setOwnerId(mutexOwnerId); + pair lastProgress = fileFTPProgressList[itemName]; + fileFTPProgressList[itemName] = pair(fileProgress,stats->currentFilename); + safeMutexFTPProgress.ReleaseLock(); + + if(itemName != "" && (lastDownloadProgress < fileProgress && fileProgress % 25 == 0)) { + lastDownloadProgress = fileProgress; + + char szBuf[8096]=""; + snprintf(szBuf,8096,"Downloaded %d%% of file: %s",fileProgress,itemName.c_str()); + console.addLine(szBuf); + } + } + } + else if(type == ftp_cct_ExtractProgress) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Got FTP extract Callback for [%s] result = %d [%s]\n",itemName.c_str(),result.first,result.second.c_str()); + printf("Got FTP extract Callback for [%s] result = %d [%s]\n",itemName.c_str(),result.first,result.second.c_str()); + + if(userdata == NULL) { + char szBuf[8096]=""; + snprintf(szBuf,8096,lang.getString("DataMissingExtractDownloadMod").c_str(),itemName.c_str()); + //printf("%s\n",szBuf); + console.addLine(szBuf,true); + } + else { + char *szBuf = (char *)userdata; + //printf("%s\n",szBuf); + console.addLine(szBuf); + } + } + else if(type == ftp_cct_TempFile) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Got FTP Callback for [%s] result = %d [%s]\n",itemName.c_str(),result.first,result.second.c_str()); + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutexFTPProgress((ftpClientThread != NULL ? ftpClientThread->getProgressMutex() : NULL),mutexOwnerId); + if(ftpClientThread != NULL && ftpClientThread->getProgressMutex() != NULL) ftpClientThread->getProgressMutex()->setOwnerId(mutexOwnerId); + fileFTPProgressList.erase(itemName); + safeMutexFTPProgress.ReleaseLock(); + + printf("### downloaded TEMP file [%s] result = %d\n",itemName.c_str(),result.first); + + if(result.first == ftp_crt_SUCCESS) { + // Get path to temp files + string tempFilePath = "temp/"; + if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") { + tempFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + tempFilePath; + } + else { + Config &config = Config::getInstance(); + string userData = config.getString("UserData_Root",""); + if(userData != "") { + endPathWithSlash(userData); + } + tempFilePath = userData + tempFilePath; + } + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Temp files path [%s]\n",tempFilePath.c_str()); + + // Delete the downloaded archive + if(fileExists(tempFilePath + itemName)) { + removeFile(tempFilePath + itemName); + } + + // Move all files into binary folder + vector fileList = getFolderTreeContentsListRecursively(tempFilePath, "", false, NULL); + for(unsigned int index = 0; index < fileList.size(); ++index) { + string fileName = fileList[index]; + string newFileName = Properties::getApplicationPath() + extractFileFromDirectoryPath(fileName); + bool result = renameFile(fileName,newFileName); + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Rename: [%s] to [%s] result = %d\n",fileName.c_str(),newFileName.c_str(),result); + } + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Successfully updated!\n"); + console.addLine("Successfully updated, please restart!",true); + } + else { + curl_version_info_data *curlVersion= curl_version_info(CURLVERSION_NOW); + + char szBuf[8096]=""; + snprintf(szBuf,8096,"FAILED to download the updates: [%s] using CURL version [%s] [%s]",itemName.c_str(),curlVersion->version,result.second.c_str()); + console.addLine(szBuf,true); + showErrorMessageBox(szBuf, "ERROR", false); + } + } +} + + void MenuStateRoot::mouseMove(int x, int y, const MouseState *ms){ popupMenu.mouseMove(x, y); buttonNewGame.mouseMove(x, y); @@ -210,6 +485,9 @@ void MenuStateRoot::mouseMove(int x, int y, const MouseState *ms){ if (errorMessageBox.getEnabled()) { errorMessageBox.mouseMove(x, y); } + if (ftpMessageBox.getEnabled()) { + ftpMessageBox.mouseMove(x, y); + } } bool MenuStateRoot::isMasterserverMode() const { @@ -290,6 +568,9 @@ void MenuStateRoot::render() { if(errorMessageBox.getEnabled()) { renderer.renderMessageBox(&errorMessageBox); } + if(ftpMessageBox.getEnabled()) { + renderer.renderMessageBox(&ftpMessageBox); + } if(program != NULL) program->renderProgramMsgBox(); } @@ -304,9 +585,104 @@ void MenuStateRoot::update() { } return; } + + if(gameUpdateChecked == false) { + gameUpdateChecked = true; + + string updateCheckURL = Config::getInstance().getString("UpdateCheckURL",""); + if(updateCheckURL != "") { + static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__); + updatesHttpServerThread = new SimpleTaskThread(this,1,200); + updatesHttpServerThread->setUniqueID(mutexOwnerId); + updatesHttpServerThread->start(); + } + } + console.update(); } +void MenuStateRoot::simpleTask(BaseThread *callingThread,void *userdata) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutexThreadOwner(callingThread->getMutexThreadOwnerValid(),mutexOwnerId); + if(callingThread->getQuitStatus() == true || safeMutexThreadOwner.isValidMutex() == false) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + return; + } + + callingThread->getMutexThreadOwnerValid()->setOwnerId(mutexOwnerId); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + + + string updateCheckURL = Config::getInstance().getString("UpdateCheckURL",""); + if(updateCheckURL != "") { + + string baseURL = updateCheckURL; + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] About to call first http url, base [%s]..\n",__FILE__,__FUNCTION__,__LINE__,baseURL.c_str()); + + CURL *handle = SystemFlags::initHTTP(); + CURLcode curlResult = CURLE_OK; + string updateMetaData = SystemFlags::getHTTP(baseURL,handle,-1,&curlResult); + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("techsMetaData [%s] curlResult = %d\n",updateMetaData.c_str(),curlResult); + + if(callingThread->getQuitStatus() == true || safeMutexThreadOwner.isValidMutex() == false) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); + return; + } + + if(curlResult != CURLE_OK) { + string curlError = curl_easy_strerror(curlResult); + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] curlError [%s]..\n",__FILE__,__FUNCTION__,__LINE__,curlError.c_str()); + + char szMsg[8096]=""; + snprintf(szMsg,8096,"An error was detected while checking for new updates\n%s",curlError.c_str()); + showErrorMessageBox(szMsg, "ERROR", false); + } + + if(curlResult == CURLE_OK || + (curlResult != CURLE_COULDNT_RESOLVE_HOST && + curlResult != CURLE_COULDNT_CONNECT)) { + + Properties props; + props.loadFromText(updateMetaData); + + int compareResult = compareMajorMinorVersion(glestVersionString, props.getString("LatestGameVersion",""),true); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("compareResult = %d local [%s] remote [%s]\n",compareResult,glestVersionString.c_str(),props.getString("LatestGameVersion","").c_str()); + + if(compareResult < 0) { + + string downloadBinaryKey = "LatestGameBinaryUpdateArchiveURL-" + getPlatformTypeNameString() + getPlatformArchTypeNameString(); + if(props.hasString(downloadBinaryKey)) { + ftpFileName = extractFileFromDirectoryPath(props.getString(downloadBinaryKey)); + ftpFileURL = props.getString(downloadBinaryKey); + } + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Checking update key downloadBinaryKey [%s] ftpFileURL [%s]\n",downloadBinaryKey.c_str(),ftpFileURL.c_str()); + + if(props.getBool("AllowUpdateDownloads","false") == false || ftpFileURL == "") { + char szMsg[8096]=""; + snprintf(szMsg,8096,"A new update was detected: %s\nUpdate Date: %s\nPlease visit megaglest.org for details!", + props.getString("LatestGameVersion","?").c_str(), + props.getString("LatestGameVersionReleaseDate","?").c_str()); + showFTPMessageBox(szMsg, "Update", false, true); + } + else { + char szMsg[8096]=""; + snprintf(szMsg,8096,"A new update was detected: %s\nUpdate Date: %s\nDownload update now?", + props.getString("LatestGameVersion","?").c_str(), + props.getString("LatestGameVersionReleaseDate","?").c_str()); + showFTPMessageBox(szMsg, "Update", false, false); + } + } + } + SystemFlags::cleanupHTTP(&handle); + } +} + void MenuStateRoot::keyDown(SDL_KeyboardEvent key) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] key = [%c] [%d]\n",__FILE__,__FUNCTION__,__LINE__,key.keysym.sym,key.keysym.sym); @@ -344,34 +720,58 @@ void MenuStateRoot::keyDown(SDL_KeyboardEvent key) { } -void MenuStateRoot::showMessageBox(const string &text, const string &header, bool toggle){ - if(!toggle){ +void MenuStateRoot::showMessageBox(const string &text, const string &header, bool toggle) { + if(toggle == false) { mainMessageBox.setEnabled(false); } - if(!mainMessageBox.getEnabled()){ + if(mainMessageBox.getEnabled() == false) { mainMessageBox.setText(text); mainMessageBox.setHeader(header); mainMessageBox.setEnabled(true); } - else{ + else { mainMessageBox.setEnabled(false); } } -void MenuStateRoot::showErrorMessageBox(const string &text, const string &header, bool toggle){ - if(!toggle){ +void MenuStateRoot::showErrorMessageBox(const string &text, const string &header, bool toggle) { + if(toggle == false) { errorMessageBox.setEnabled(false); } - if(!errorMessageBox.getEnabled()){ + if(errorMessageBox.getEnabled() == false) { errorMessageBox.setText(text); errorMessageBox.setHeader(header); errorMessageBox.setEnabled(true); } - else{ + else { errorMessageBox.setEnabled(false); } } +void MenuStateRoot::showFTPMessageBox(const string &text, const string &header, bool toggle, bool okOnly) { + if(toggle == false) { + ftpMessageBox.setEnabled(false); + } + + Lang &lang= Lang::getInstance(); + if(okOnly) { + ftpMessageBox.init(lang.getString("Ok")); + } + else { + ftpMessageBox.init(lang.getString("Yes"), lang.getString("No")); + } + + if(ftpMessageBox.getEnabled() == false) { + ftpMessageBox.setText(text); + ftpMessageBox.setHeader(header); + ftpMessageBox.setEnabled(true); + } + else { + ftpMessageBox.setEnabled(false); + } +} + + }}//end namespace diff --git a/source/glest_game/menu/menu_state_root.h b/source/glest_game/menu/menu_state_root.h index 23aa073a..71811fa4 100644 --- a/source/glest_game/menu/menu_state_root.h +++ b/source/glest_game/menu/menu_state_root.h @@ -13,6 +13,9 @@ #define _GLEST_GAME_MENUSTATEROOT_H_ #include "main_menu.h" +#include "simple_threads.h" +#include "miniftpclient.h" + #include "leak_dumper.h" namespace Glest{ namespace Game{ @@ -24,7 +27,7 @@ namespace Glest{ namespace Game{ class GraphicMessageBox; class PopupMenu; -class MenuStateRoot: public MenuState { +class MenuStateRoot: public MenuState, public SimpleTaskCallbackInterface, public FTPClientCallbackInterface { private: GraphicButton buttonNewGame; GraphicButton buttonLoadGame; @@ -36,20 +39,36 @@ private: GraphicMessageBox mainMessageBox; GraphicMessageBox errorMessageBox; + GraphicMessageBox ftpMessageBox; PopupMenu popupMenu; + static bool gameUpdateChecked; + SimpleTaskThread *updatesHttpServerThread; + FTPClientThread *ftpClientThread; + std::map > fileFTPProgressList; + string ftpFileName; + string ftpFileURL; + int lastDownloadProgress; + + virtual void simpleTask(BaseThread *callingThread,void *userdata); + void startFTPClientIfRequired(); + virtual void FTPClient_CallbackEvent(string itemName, + FTP_Client_CallbackType type, pair result,void *userdata); + public: MenuStateRoot(Program *program, MainMenu *mainMenu); + virtual ~MenuStateRoot(); void mouseClick(int x, int y, MouseButton mouseButton); void mouseMove(int x, int y, const MouseState *mouseState); void render(); void update(); virtual void keyDown(SDL_KeyboardEvent key); - void showMessageBox(const string &text, const string &header, bool toggle); + void showMessageBox(const string &text, const string &header, bool toggle); void showErrorMessageBox(const string &text, const string &header, bool toggle); + void showFTPMessageBox(const string &text, const string &header, bool toggle, bool okOnly); virtual bool isMasterserverMode() const; virtual void reloadUI(); diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index cddec1fe..86521e8b 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -2692,14 +2692,16 @@ const Resource *World::getResourceForTeam(const ResourceType *rt, int teamIndex) Faction *faction = factions[index]; if(faction != NULL && faction->getTeam() == teamIndex) { - const Resource *factionResource = faction->getResource(rt,true); - if(factionResource != NULL && factionResource->getType() != NULL) { + if(faction->hasAliveUnits(true,true)) { + const Resource *factionResource = faction->getResource(rt,true); + if(factionResource != NULL && factionResource->getType() != NULL) { - int teamResourceAmount = teamResource.getAmount(); - int teamResourceBalance = teamResource.getBalance(); + int teamResourceAmount = teamResource.getAmount(); + int teamResourceBalance = teamResource.getBalance(); - teamResource.setAmount(teamResourceAmount + factionResource->getAmount()); - teamResource.setBalance(teamResourceBalance + factionResource->getBalance()); + teamResource.setAmount(teamResourceAmount + factionResource->getAmount()); + teamResource.setBalance(teamResourceBalance + factionResource->getBalance()); + } } } } diff --git a/source/shared_lib/include/util/properties.h b/source/shared_lib/include/util/properties.h index 8aa3b272..038facfe 100644 --- a/source/shared_lib/include/util/properties.h +++ b/source/shared_lib/include/util/properties.h @@ -54,6 +54,9 @@ private: static string scenarioPath; static string tutorialPath; +protected: + void processTextLine(bool is_utf8_language, char *lineBuffer); + public: static void setApplicationPath(string value) { applicationPath=value; } static string getApplicationPath() { return applicationPath; } @@ -72,6 +75,8 @@ public: static string getTutorialPath() { return tutorialPath; } void clear(); + + void loadFromText(const string &text); void load(const string &path,bool clearCurrentProperties=true); void save(const string &path); diff --git a/source/shared_lib/include/util/util.h b/source/shared_lib/include/util/util.h index 5e3c0c7c..b77a328f 100644 --- a/source/shared_lib/include/util/util.h +++ b/source/shared_lib/include/util/util.h @@ -239,7 +239,7 @@ float saturate(float value); int round(float f); //misc -int compareMajorMinorVersion(string versionA,string versionB); +int compareMajorMinorVersion(string versionA,string versionB, bool checkForNewVersionUpdates=false); int getMajor(string version); int getMinor(string version); bool checkVersionComptability(string clientVersionString, string serverVersionString); diff --git a/source/shared_lib/sources/platform/posix/miniftpclient.cpp b/source/shared_lib/sources/platform/posix/miniftpclient.cpp index adcd6acf..d413aaa5 100644 --- a/source/shared_lib/sources/platform/posix/miniftpclient.cpp +++ b/source/shared_lib/sources/platform/posix/miniftpclient.cpp @@ -845,6 +845,8 @@ pair FTPClientThread::getFileInternalFromServer(p pair result = getFileFromServer(ftp_cct_File, fileName,remotePath, destFileSaveAs, "", ""); + //printf("Got file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first); + // Extract the archive if(result.first == ftp_crt_SUCCESS) { string ext = extractExtension(destFileSaveAs); @@ -897,10 +899,18 @@ pair FTPClientThread::getTempFileInternalFromServ destFileSaveAs += fileName.first; string remotePath = fileName.second; - fileName.second = ""; - pair result = getFileFromServer(ftp_cct_TempFile, - fileName,remotePath, destFileSaveAs, FTP_TEMPFILES_USERNAME, FTP_COMMON_PASSWORD); + //printf("First [%s] Second [%s]\n",fileName.first.c_str(),fileName.second.c_str()); + pair result; + if(StartsWith(remotePath,"http://")) { + result = getFileFromServer(ftp_cct_TempFile, fileName,remotePath, destFileSaveAs, "", ""); + } + else { + fileName.second = ""; + result = getFileFromServer(ftp_cct_TempFile,fileName,remotePath, destFileSaveAs, FTP_TEMPFILES_USERNAME, FTP_COMMON_PASSWORD); + } + + //printf("Got temp file [%s] result.first = %d\n",destFileSaveAs.c_str(),result.first); // Extract the archive if(result.first == ftp_crt_SUCCESS) { diff --git a/source/shared_lib/sources/util/properties.cpp b/source/shared_lib/sources/util/properties.cpp index 1e9096b1..aae62f7c 100644 --- a/source/shared_lib/sources/util/properties.cpp +++ b/source/shared_lib/sources/util/properties.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "conversion.h" #include "util.h" @@ -31,7 +33,6 @@ #include "utf8.h" #include "font.h" #include "string_utils.h" - #include "leak_dumper.h" using namespace std; @@ -56,8 +57,6 @@ string Properties::tutorialPath = ""; void Properties::load(const string &path, bool clearCurrentProperties) { char lineBuffer[maxLine]=""; - string line, key, value, original_value; - size_t pos=0; this->path= path; bool is_utf8_language = valid_utf8_file(path.c_str()); @@ -88,80 +87,7 @@ void Properties::load(const string &path, bool clearCurrentProperties) { fileStream.getline(lineBuffer, maxLine); lineBuffer[maxLine-1]='\0'; - //printf("\n[%ls]\n",lineBuffer); - //printf("\n[%s]\n",&lineBuffer[0]); - - if(lineBuffer[0] != '\0') { - // If the file is NOT in UTF-8 format convert each line - if(is_utf8_language == false && Font::forceLegacyFonts == false) { - char *utfStr = ConvertToUTF8(&lineBuffer[0]); - - //printf("\nBefore [%s] After [%s]\n",&lineBuffer[0],utfStr); - - memset(&lineBuffer[0],0,maxLine); - memcpy(&lineBuffer[0],&utfStr[0],strlen(utfStr)); - - delete [] utfStr; - } - else if(is_utf8_language == true && Font::forceLegacyFonts == true) { - char *asciiStr = ConvertFromUTF8(&lineBuffer[0]); - - //printf("\nBefore [%s] After [%s]\n",&lineBuffer[0],utfStr); - - memset(&lineBuffer[0],0,maxLine); - memcpy(&lineBuffer[0],&asciiStr[0],strlen(asciiStr)); - - delete [] asciiStr; - } - } - - //process line if it it not a comment - if(lineBuffer[0] != ';' && lineBuffer[0] != '#') { - //wstring wstr = lineBuffer; - //line.assign(wstr.begin(),wstr.end()); - - // gracefully handle win32 \r\n line endings - size_t len= strlen(lineBuffer); - if(len > 0 && lineBuffer[len-1] == '\r') { - lineBuffer[len-1]= 0; - } - - line= lineBuffer; - pos= line.find('='); - - if(pos != string::npos){ - key= line.substr(0, pos); - value= line.substr(pos+1); - original_value = value; - - if(applyTagsToValue(value) == true) { - if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Property key [%s] now has value [%s] original_value [%s]\n",key.c_str(),value.c_str(),original_value.c_str()); - } - - bool replaceExisting = false; - if(propertyMap.find(key) != propertyMap.end()) { - replaceExisting = true; - } - propertyMap[key] = original_value; - propertyMapTmp[key] = value; - - if(replaceExisting == false) { - propertyVector.push_back(PropertyPair(key, original_value)); - propertyVectorTmp.push_back(PropertyPair(key, value)); - } - else { - for(unsigned int i = 0; i < propertyVector.size(); ++i) { - PropertyPair ¤tPair = propertyVector[i]; - if(currentPair.first == key) { - currentPair.second = original_value; - - propertyVectorTmp[i].second = value; - break; - } - } - } - } - } + processTextLine(is_utf8_language,lineBuffer); } fileStream.close(); @@ -172,6 +98,108 @@ void Properties::load(const string &path, bool clearCurrentProperties) { #endif } +void Properties::loadFromText(const string &text) { + bool is_utf8_language = false; + + char lineBuffer[maxLine]=""; + + std::istringstream textStream(text); + while(textStream.eof() == false) { + //lineBuffer[0]='\0'; + std::string lineText; + getline(textStream, lineText); + if(lineText.length() > 0) { + memset(&lineBuffer[0],0,maxLine); + memcpy(&lineBuffer[0],&lineText[0],lineText.length()); + + //fileStream.getline(lineBuffer, maxLine); + //lineBuffer[maxLine-1]='\0'; + + processTextLine(is_utf8_language,&lineBuffer[0]); + } + } +} + +void Properties::processTextLine(bool is_utf8_language, char *lineBuffer) { + //printf("\n[%ls]\n",lineBuffer); + //printf("\n[%s]\n",&lineBuffer[0]); + + string line, key, value, original_value; + size_t pos=0; + + if(lineBuffer != NULL && lineBuffer[0] != '\0') { + // If the file is NOT in UTF-8 format convert each line + if(is_utf8_language == false && Font::forceLegacyFonts == false) { + char *utfStr = ConvertToUTF8(&lineBuffer[0]); + + //printf("\nBefore [%s] After [%s]\n",&lineBuffer[0],utfStr); + + memset(&lineBuffer[0],0,maxLine); + memcpy(&lineBuffer[0],&utfStr[0],strlen(utfStr)); + + delete [] utfStr; + } + else if(is_utf8_language == true && Font::forceLegacyFonts == true) { + char *asciiStr = ConvertFromUTF8(&lineBuffer[0]); + + //printf("\nBefore [%s] After [%s]\n",&lineBuffer[0],utfStr); + + memset(&lineBuffer[0],0,maxLine); + memcpy(&lineBuffer[0],&asciiStr[0],strlen(asciiStr)); + + delete [] asciiStr; + } + } + + //process line if it it not a comment + if(lineBuffer != NULL && lineBuffer[0] != ';' && lineBuffer[0] != '#') { + //wstring wstr = lineBuffer; + //line.assign(wstr.begin(),wstr.end()); + + // gracefully handle win32 \r\n line endings + size_t len= strlen(lineBuffer); + if(len > 0 && lineBuffer[len-1] == '\r') { + lineBuffer[len-1]= 0; + } + + line= lineBuffer; + pos= line.find('='); + + if(pos != string::npos){ + key= line.substr(0, pos); + value= line.substr(pos+1); + original_value = value; + + if(applyTagsToValue(value) == true) { + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Property key [%s] now has value [%s] original_value [%s]\n",key.c_str(),value.c_str(),original_value.c_str()); + } + + bool replaceExisting = false; + if(propertyMap.find(key) != propertyMap.end()) { + replaceExisting = true; + } + propertyMap[key] = original_value; + propertyMapTmp[key] = value; + + if(replaceExisting == false) { + propertyVector.push_back(PropertyPair(key, original_value)); + propertyVectorTmp.push_back(PropertyPair(key, value)); + } + else { + for(unsigned int i = 0; i < propertyVector.size(); ++i) { + PropertyPair ¤tPair = propertyVector[i]; + if(currentPair.first == key) { + currentPair.second = original_value; + + propertyVectorTmp[i].second = value; + break; + } + } + } + } + } +} + std::map Properties::getTagReplacementValues(std::map *mapExtraTagReplacementValues) { std::map mapTagReplacementValues; diff --git a/source/shared_lib/sources/util/util.cpp b/source/shared_lib/sources/util/util.cpp index 06c1a70e..0d8cdd51 100644 --- a/source/shared_lib/sources/util/util.cpp +++ b/source/shared_lib/sources/util/util.cpp @@ -787,54 +787,70 @@ int round(float f){ } // ==================== misc ==================== -int compareMajorMinorVersion(string versionA,string versionB){ - int majorA=getMajor(versionA); - int minorA=getMinor(versionA); - int majorB=getMajor(versionB); - int minorB=getMinor(versionB); +int compareMajorMinorVersion(string versionA,string versionB, bool checkForNewVersionUpdates) { + int majorA = getMajor(versionA); + int minorA = getMinor(versionA); + int majorB = getMajor(versionB); + int minorB = getMinor(versionB); - if(majorA parts=split(version.substr(1),"."); +int getMajor(string version) { + vector parts = split(version.substr(1),"."); - if(parts.size()>2 && parts[0] != "" && IsNumeric(parts[0].c_str(),false)) + if(parts.size() > 2 && parts[0] != "" && IsNumeric(parts[0].c_str(),false)) { return strToInt(parts[0]); - else + } + else { return 0; + } } -int getMinor(string version){ - vector parts=split(version.substr(1),"."); - if(parts.size()>2 && parts[1] != ""){ +int getMinor(string version) { + vector parts = split(version.substr(1),"."); + if(parts.size() > 2 && parts[1] != "") { string resultStr=""; for (int i = 0; i < (int)parts[1].length(); ++i) { // just add leading numbers - if(IsNumeric((resultStr+parts[1][i]).c_str(),false) ) + if(IsNumeric((resultStr + parts[1][i]).c_str(),false) ) { resultStr += parts[1][i]; - else + } + else { break; + } } - if(resultStr=="") + if(resultStr == "") { return 0; - else + } + else { return strToInt(resultStr); + } } - else + else { return 0; + } } bool checkVersionComptability(string clientVersionString, string serverVersionString) {