#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;
}