#define DEBUG /* AE\Mod Installer. Needs getPackages() now! */ //#include #include #include #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/filesystem.hpp" // includes all needed Boost.Filesystem declarations #include // for std::cout // for ease of tutorial presentation; // a namespace alias is preferred practice in real code #include #include #include "methods.h" #include #include #include #ifdef WIN32 #include "Include\dirent.h" #include static const string Onisplit = "Onisplit.exe"; string import = "-import:nosep"; #else #include #include //??? is this included for Macs? string import = "-import:sep"; static const string Onisplit = "./mono Onisplit.exe"; #endif using namespace boost::filesystem; using namespace std; //bool FALSE = 0; //bool TRUE = 0; const bool SPLIT = 1; const bool NOT_SPLIT = 0; bool splitInstances = SPLIT; int main(void) { // SetConsoleTitle("AE Installer"); windows junk, convert to SDL // system("color 0A"); cout << "\nWelcome to the AE installer!\n"; cout << "\nWhat would you like to do?\n"; return mainMenu(); } vector getPackages(void) { vector packages; packages.reserve(65536); //comeon, we shouldn't need this much space...right?! fstream file; #ifdef DEBUG #ifdef WIN32 string path = ".\\packages"; //only for my build. :P _chdir(path.c_str()); _chdir(".."); cout << path; #else string path = "K:\\Oni\\edition\\install\\packages"; //change this, 'scen. #endif #else string path = "."; #endif string filename = "\0"; string MODINFO_CFG = "\\Mod_Info.cfg"; DIR *pdir; struct dirent *pent; pdir = opendir( path.c_str() ); //"." refers to the current dir if (!pdir){ printf ("\nopendir() failure; terminating"); exit(1); } errno=0; while (( pent = readdir(pdir) )){ filename = path + '\\' + pent->d_name + MODINFO_CFG; file.open(filename.c_str()); //cout << filename << "\n"; if(!file.fail() ) { //file.open(filename.c_str(), fstream::out); //do stuff like adding to vector :P //would prefer to push a pointer to a package, but this will do for now packages.push_back( fileToModPackage(file) ); } file.close(); file.clear(); } if (errno){ printf ("readdir() failure; terminating"); exit(1); } closedir(pdir); return packages; } ModPackage fileToModPackage(fstream &file) { /* This converts a file to a ModPackage struct. A few notes... "iter" is the current word we are on. I should have named it "token" or something, but I don't have multiple iterators, so its ok. I refer to (*iter) at the beginning of each if statement block. I could probably store it as a variable, but I'm pretty sure that dereferencing a pointer\iterator isn't much slower than reading a variable. */ ModPackage package; string line; static string NameOfMod = "NameOfMod"; //used for comparing to the current token... //I could have done it in reverse (*iter).compare("ModString") or static string ARROW = "->"; //did something like "ModString".compare(*iter), and it would have been static string ModString = "ModString"; //functionably the same. static string HasOnis = "HasOnis"; static string HasDeltas = "HasDeltas"; static string HasBSL = "HasBSL"; static string HasDats = "HasDats"; static string IsEngine = "IsEngine"; static string Readme = "Readme"; static string GlobalNeeded = "GlobalNeeded"; static string Category = "Category"; static string Creator = "Creator"; while (! file.eof() ) { getline (file,line); vector tokens; vector::iterator iter; Tokenize(line, tokens); //string to vector of "words" if (tokens.capacity() >= 2) { //make sure they are using enough stuff iter = tokens.begin(); //what word we are on, starts at first word /* if (!AEInstallVersion.compare(*iter)) If mod is too old, skip this mod. */ /*else*/if (!NameOfMod.compare(*iter)) { //if it contains the name for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++) { //interates through the words, ends if it reaches the end of the line or a "//" comment if (ARROW.compare(*iter) && NameOfMod.compare(*iter)) { //ignores "->" and "NameOfMod" //cout << *iter; //cout << " "; package.name += *iter + " "; } } } else if (!ModString.compare(*iter)) { iter++; iter++; package.modStringName = *iter; iter++; package.modStringVersion = atoi((*iter).c_str()); } else if (!HasOnis.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.hasOnis = 1; //Gotta love c++'s lack of a standard case-insensitive string comparer...I know my implementation here sucks. I need to change it to check each character one by one. At the moment, using "YFR" would probably set it off. :< } else if (!HasBSL.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.hasBSL = 1; } else if (!HasDeltas.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.hasDeltas = 1; } else if (!HasDats.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.hasDats = 1; } else if (!IsEngine.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.isEngine = 1; } else if (!GlobalNeeded.compare(*iter)) { iter++; iter++; if (toupper((*iter)[0]) + toupper((*iter)[1]) + toupper((*iter)[2]) == 'Y' + 'E' + 'S') package.globalNeeded = 1; else if (toupper((*iter)[0]) + toupper((*iter)[1]) == 'N' + 'O') package.globalNeeded = 1; //Really the only place where checking for "No" is important atm. } else if (!Category.compare(*iter)) { for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++) { //interates through the words, ends if it reaches the end of the line or a "//" comment if (ARROW.compare(*iter) && Category.compare(*iter)) { //ignores "->" and "Category" //cout << *iter; //cout << " "; package.category += *iter + " "; } } } else if (!Creator.compare(*iter)) { //if it contains the name for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++) { //interates through the words, ends if it reaches the end of the line or a "//" comment if (ARROW.compare(*iter) && Creator.compare(*iter)) { //ignores "->" and "Category" //cout << *iter; //cout << " "; package.creator += *iter + " "; } } } else if (!Readme.compare(*iter)) { //if it contains the name for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++) { //interates through the words, ends if it reaches the end of the line or a "//" comment if (ARROW.compare(*iter) && Readme.compare(*iter)) { //ignores "->" and "Category" //cout << *iter; //cout << " "; package.readme += *iter + " "; } } } } } package.doOutput(); return package; } int mainMenu(void) { int choice = '0'; bool ok = FALSE; cout << "1. Install new packages\n"; cout << "2. Uninstall packages\n"; cout << "3. See what is installed\n"; cout << "4. About AE\n"; cout << "5. Quit\n\n"; do { ok = TRUE; choice = cin.get(); cin.ignore(128, '\n'); switch(choice) { case '1': installPackages(); break; case '2': uninstallPackages(); break; case '3': //listInstalledPackages(); break; case '5': return 0; default: ok = FALSE; } } while(ok == FALSE); return 0; } void installPackages() { ModPackage package; vector installed_packages; vector packages; vector::iterator iter; iter = packages.begin(); vector installString; packages = getPackages(); vector installedMods = getInstallString(); if (packages.empty()) { cout << "Error: You have no packages!\n"; return; } cout << "Detecting installed packages...\n"; int index = 1; char choice = '0'; for (vector::iterator package_iter = packages.begin(); package_iter != packages.end(); ++package_iter) { if (!binary_search(installedMods.begin(), installedMods.end(), package_iter->modStringName)) { //package_iter->isInstalled :< I forgot about this... //cout << index << " "; system("cls"); cout << (*package_iter).name <<"\n"; for( int character = 1; character <= (*package_iter).name.length() - 1; character++) cout << char(196); //does extended ASCII work in UNIX? cout << "\n" << (*package_iter).readme << "\n" << "\n" << "Please enter a number choice\n" << " 1. Install\n" << " 2. Don't Install\n" << ""; index++; choice = 0; do { choice = cin.get(); cin.ignore(1280, '\n'); } while(choice == 0); if (choice == '1') { cout << "\nInstalling...\n\n"; if ( package_iter->hasOnis || ( package_iter->hasDeltas /*(*package_iter).isUnpacked */ )) { installedMods.push_back(package_iter->modStringName); system("PAUSE"); } } } } if (index == 1) { cout << "Error: All packages are already installed\n"; return; } sort(installedMods.begin(), installedMods.end()); //system(Onisplit.c_str()); RecompileAll(installedMods); system("PAUSE"); } void uninstallPackages() { ; } void getInstalledPackages() { ; } void RecompileAll(vector installedMods) { cout << "Recompiling Data...\n"; path vanilla_dir = "./packages/VanillaDats/"; string importCommand = ""; if(splitInstances == SPLIT){ recursive_directory_iterator end_iter; try { for ( recursive_directory_iterator dir_itr( vanilla_dir ); dir_itr != end_iter; ++dir_itr ) { try { if ( is_directory( dir_itr->status() ) && dir_itr.level() == 1) { importCommand = Onisplit + " " + import + " " + dir_itr->path().parent_path().string() + '/' + dir_itr->path().filename(); for (int i = 0; i < installedMods.size(); ++i) { if (exists("packages/" + installedMods[i] + "/oni/" + dir_itr->path().parent_path().filename() + '/' + dir_itr->path().filename() )) importCommand += " packages/" + installedMods[i] + "/oni/" + dir_itr->path().parent_path().filename() + '/' + dir_itr->path().filename(); //else cout << " packages/VanillaDats/" + installedMods[i] + "/oni/"; } importCommand += " ../GameDataFolder/" + dir_itr->path().filename() + ".dat"; system(importCommand.c_str()); //cout << importCommand << "\n"; } } catch ( const std::exception & ex ) { cout << "Warning, exception " << ex.what() << "!"; } } } catch( const std::exception & ex ) { cout << "Warning, exception " << ex.what() << "!\n" << "You probably need to reGlobalize.; create_directory( "./packages/VanillaDats" ); } } else if(splitInstances == NOT_SPLIT){ directory_iterator end_iter; for ( directory_iterator dir_itr( vanilla_dir ); dir_itr != end_iter; ++dir_itr ) { try { if ( is_directory( dir_itr->status() ) ) { system((Onisplit + " " + import + " " + vanilla_dir.string() + dir_itr->path().filename() + " " + "../GameDataFolder/" + dir_itr->path().filename() + ".dat").c_str()); } } catch ( const std::exception & ex ) { cout << "Warning, something odd happened!\n"; } } } } vector getInstallString() { system("PAUSE"); vector returnval; string file_name = "../GameDataFolder/ImportList.cfg"; string line; fstream file; if( exists(file_name) ) { file.open(file_name.c_str()); getline (file,line); Tokenize(line, returnval); file.close(); file.clear(); sort(returnval.begin(), returnval.end()); } else cout << "fail"; return returnval; }