From dcab3b681b15d2c3f6d026e2ced1ed6b0a12046e Mon Sep 17 00:00:00 2001 From: kervala Date: Thu, 5 Aug 2010 09:53:38 +0200 Subject: [PATCH] Changed: #1051 Create a console-based working patcher --- .../tools/client/client_patcher/main.cpp | 164 ++++++++++++++---- 1 file changed, 130 insertions(+), 34 deletions(-) diff --git a/code/ryzom/tools/client/client_patcher/main.cpp b/code/ryzom/tools/client/client_patcher/main.cpp index d4de6fa2b..d944204ed 100644 --- a/code/ryzom/tools/client/client_patcher/main.cpp +++ b/code/ryzom/tools/client/client_patcher/main.cpp @@ -1,6 +1,7 @@ #include "stdpch.h" #include "login_patch.h" #include "client_cfg.h" +#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -26,10 +27,32 @@ uint32 LoginShardId = 0xFFFFFFFF; // stuff which is defined in other .cpp files extern void tmpFlagRemovedPatchCategories(NLMISC::CConfigFile &cf); +bool useUtf8 = false; + +std::string convert(const ucstring &str) +{ + if (useUtf8) + return str.toUtf8(); + + return str.toString(); +} + +void printError(const std::string &str) +{ + // display error in red + printf("\033[22;31mError: %s\033[0m\n", str.c_str()); +} + +void printProgress(const std::string &str) +{ + // display progress in green + printf("\033[F\033[22;31mError: %d\033[0m\033[[1J\n", str.c_str()); +} + int main(int argc, char *argv[]) { // init the Nel context - CApplicationContext *appContext = new CApplicationContext; + CApplicationContext appContext; createDebug(); @@ -48,25 +71,75 @@ int main(int argc, char *argv[]) CPath::setCurrentPath(currentPath); } + std::string lang; + + char *locale = setlocale(LC_CTYPE, NULL); + + if (locale) + lang = toLower(std::string(locale)); + useUtf8 = (lang.find("utf8") != string::npos || lang.find("utf-8") != string::npos); + + // create or load client.cfg ClientCfg.init("client.cfg"); + // check if PatchServer is defined + if (ClientCfg.PatchServer.empty()) + { + printError("PatchServer not defined in client_default.cfg or client.cfg"); + return 1; + } + + // set default paths std::string dataPath = "./data/"; std::string rootPath = "./"; + // use custom data path if specified if (!ClientCfg.DataPath.empty()) { - dataPath = CPath::standardizePath(ClientCfg.DataPath[0]); + dataPath = CPath::standardizePath(ClientCfg.DataPath.front()); string::size_type pos = dataPath.rfind('/', dataPath.length()-2); if (pos != string::npos) rootPath = dataPath.substr(0, pos+1); } - // add .bnp containing translations - CPath::addSearchBigFile(dataPath + "gamedev.bnp", true, false); + std::string unpackPath = CPath::standardizePath(rootPath + "unpack"); + + // check if user can write in data directory + if (!CFile::isExists(unpackPath)) + { + if (!CFile::createDirectoryTree(unpackPath)) + { + printError("You don't have permission to create " + unpackPath); + return 1; + } + } + else + { + if (!CFile::createEmptyFile(unpackPath + "empty")) + { + printError("You don't have write permission in " + unpackPath); + return 1; + } + + CFile::deleteFile(unpackPath + "empty"); + } + + // only use PreDataPath for looking paths + if (!ClientCfg.PreDataPath.empty()) + { + for(uint i = 0; i < ClientCfg.PreDataPath.size(); ++i) + { + CPath::addSearchPath(ClientCfg.PreDataPath[i], true, false); + } + } // load translation CI18N::load(ClientCfg.LanguageCode); + printf("Checking %s files to patch...\n", convert(CI18N::get("TheSagaOfRyzom")).c_str()); + + printf("Using language: %s\n", convert(CI18N::get("LanguageName")).c_str()); + #ifdef NL_OS_UNIX // don't use cfg, exe and dll from Windows version CConfigFile::CVar var; @@ -84,8 +157,10 @@ int main(int argc, char *argv[]) // initialize patch manager and set the ryzom full path, before it's used CPatchManager *pPM = CPatchManager::getInstance(); + // set the correct root path pPM->setClientRootPath(rootPath); + // use PatchServer URL vector patchURLs; pPM->init(patchURLs, ClientCfg.PatchServer, ClientCfg.PatchVersion); pPM->startCheckThread(true /* include background patchs */); @@ -105,19 +180,15 @@ int main(int argc, char *argv[]) { for(uint i = 0; i < log.size(); ++i) { - printf("%s\n", log[i].toUtf8().c_str()); + printf("%s\n", convert(log[i]).c_str()); } } + } - if (!res) - { - ucstring errMsg = CI18N::get("uiErrChecking"); - if (!pPM->getLastErrorMessage().empty()) - { - ucstring errMsg = pPM->getLastErrorMessage(); - printf("Error: %s\n", errMsg.toUtf8().c_str()); - } - } + if (!res && !pPM->getLastErrorMessage().empty()) + { + printError(convert(CI18N::get("uiErrChecking") + " " + pPM->getLastErrorMessage())); + return 1; } CPatchManager::SPatchInfo InfoOnPatch; @@ -125,18 +196,17 @@ int main(int argc, char *argv[]) // Check is good now ask the player if he wants to apply the patch pPM->getInfoToDisp(InfoOnPatch); - uint AvailablePatchs = InfoOnPatch.getAvailablePatchsBitfield(); - // Get the list of optional categories to patch vector vCategories; for(uint i = 0; i < InfoOnPatch.OptCat.size(); i++) { // Ok for the moment all optional categories must be patched even if the player - // does not want it. Because we cant detect that a continent have to be patched ingame. + // does not want it. Because we can't detect that a continent have to be patched ingame. vCategories.push_back(InfoOnPatch.OptCat[i].Name); } + // start patch thread pPM->startPatchThread(vCategories, true); res = false; @@ -150,30 +220,58 @@ int main(int argc, char *argv[]) if (pPM->getThreadState(state, log)) { - printf("%s\n", state.toUtf8().c_str()); + printProgress(convert(state)); for(uint i = 0; i < log.size(); ++i) { - printf("%s\n", log[i].toUtf8().c_str()); - } - } - - if (!res) - { - ucstring errMsg = CI18N::get("uiErrChecking"); - if (!pPM->getLastErrorMessage().empty()) - { - ucstring errMsg = pPM->getLastErrorMessage(); - printf("Error: %s\n", errMsg.toUtf8().c_str()); + printf("%s\n", convert(log[i]).c_str()); } } } + if (!res && !pPM->getLastErrorMessage().empty()) + { + printError(convert(CI18N::get("uiErrPatching") + " " + pPM->getLastErrorMessage())); + return 1; + } + if (CPatchManager::getInstance()->mustLaunchBatFile()) { - // move downloaded files to final location - pPM->createBatchFile(pPM->getDescFile(), false, false); - CFile::createEmptyFile("show_eula"); + std::string error; + + try + { + // move downloaded files to final location + pPM->createBatchFile(pPM->getDescFile(), false, false); + CFile::createEmptyFile("show_eula"); + + if (!pPM->getLastErrorMessage().empty()) + { + error = convert(pPM->getLastErrorMessage()); + } + } + catch(const EDiskFullError &) + { + error = convert(CI18N::get("uiPatchDiskFull"));; + } + catch(const EWriteError &) + { + error = convert(CI18N::get("uiPatchWriteError"));; + } + catch(const Exception &e) + { + error = convert(CI18N::get("uiCheckEndWithErr") + " " + e.what()); + } + catch(...) + { + error = "unknown exception"; + } + + if (!error.empty()) + { + printError(convert(CI18N::get("uiErrPatchApply")) + " " + error); + return 1; + } } /* @@ -184,8 +282,6 @@ int main(int argc, char *argv[]) pPM->askForStopScanDataThread(); */ - delete appContext; - return 0; }