BadCompany2.MasterServer/source/Framework/Stats.cpp

367 lines
10 KiB
C++
Raw Permalink Normal View History

2015-10-10 17:08:19 +02:00
#include "Stats.h"
#include "Logger.h"
#include "Framework.h"
#include <fstream>
#include <boost/filesystem/operations.hpp>
extern Logger* debug;
extern Framework* fw;
extern bool useTemplate;
Stats::Stats()
{
}
Stats::Stats(string email, string persona, bool createNew, bool initOnly)
{
this->email = email;
this->persona = persona;
string statsName = "./templates/stats";
if(fw->emuCfg().all_stats_unlocked)
statsName.append("_unlocked");
path = "./database/";
path.append(email);
path.push_back('/');
path.append(persona);
dogtagPath = path;
path.append(".cfg");
dogtagPath.append(".dog");
ifstream statsFile(path, ifstream::in);
if(statsFile.is_open() && statsFile.good())
{
if(!initOnly)
{
stringstream buffer;
buffer << statsFile.rdbuf();
data = buffer.str();
statsFile.close();
if(data.empty()) //if the stats file is empty or cannot be opened we have to get default stats somewhere
{
debug->warning(2, DEBUG, "Persona Stats file \"%s\" data corrupted, loading default stats from template...", path.c_str());
buffer.clear();
ifstream defaultFile(statsName, ifstream::in);
if(defaultFile.is_open() && defaultFile.good())
{
buffer << defaultFile.rdbuf();
data = buffer.str();
defaultFile.close();
}
else
debug->warning(1, DEBUG, "Could not get default stats, logout asap with the client and check all the files locations!");
}
}
else
data = "";
}
else
{
if(!createNew)
{
debug->warning(1, DEBUG, "Could not find persona file '%s', creating new one...", path.c_str());
filesystem::path source_path(statsName), dest_path(path);
if(!filesystem::exists(source_path))//copyFile("./templates/stats", path.c_str()))
debug->warning(1, DEBUG, "Could not get default stats, logout asap with the client and check all the files locations!");
else
filesystem::copy_file(source_path, dest_path);
if(!filesystem::exists(dest_path))
debug->warning(1, DEBUG, "Failed to copy the default stats to %s, check you access permissions!", path.c_str());
else
{
ifstream statsFile(path, ifstream::in);
if(statsFile.is_open() && statsFile.good())
{
if(!initOnly)
{
stringstream buffer;
buffer << statsFile.rdbuf();
data = buffer.str();
statsFile.close();
if(data.empty()) //if the stats file is empty or cannot be opened we have to get default stats somewhere
debug->warning(2, DEBUG, "Persona Stats file \"%s\" data corrupted, check your template file!!", path.c_str());
}
else
data = "";
}
}
}
else
{
bool error = false;
//if we create a new file then we don't want to load stats
filesystem::path source_path(statsName), dest_path(path);
if(!filesystem::exists(source_path))
debug->warning(1, DEBUG, "Could not get default stats, logout asap with the client and check all the files locations!");
else
filesystem::copy_file(source_path, dest_path);
if(!filesystem::exists(dest_path))
debug->warning(1, DEBUG, "Failed to copy the default stats to %s, check you access permissions!", path.c_str());
else
{
if(!error)
debug->notification(2, DEBUG, "Created new persona file '%s'", path.c_str());
ofstream dogFile(dogtagPath, ios::out | ios::trunc);
if(!dogFile.is_open())
{
debug->warning(2, DEBUG, "Couldn't create dogtag file for '%s'", persona.c_str());
error = true;
}
else
dogFile.close();
if(!error)
debug->notification(2, DEBUG, "Created new dogtag file '%s'", dogtagPath.c_str());
}
}
}
}
void Stats::saveStats()
{
string tempFile = path;
tempFile.append(".bak");
filesystem::path source_path(path), dest_path(tempFile);
filesystem::copy_file(source_path, dest_path);
if(!filesystem::exists(dest_path))
return;
bool done = false;
ofstream statsFile(path, ofstream::out | ofstream::trunc); //we delete all content, is it safe to do this?
if(statsFile.is_open() && statsFile.good())
{
statsFile.write(data.c_str(), data.size());
if(!statsFile.bad())
done = true;
statsFile.close();
}
if(!done)
filesystem::copy_file(dest_path, source_path, filesystem::copy_option::overwrite_if_exists);
filesystem::remove(dest_path);
}
string Stats::getKey(string key)
{
size_t start = 0, end = 0;
string result = "";
while((start = data.find(key, start)) != string::npos) // only check for newline at start if we have a pos > 1
{
if((start == 0 || data[start-1] == '\n') && (start+key.size() < data.size() && data[start+key.size()] == '='))
break;
//debug->notification(2, DEBUG, "GetKey(), key=%s, start=%i, end=%i", key.c_str(), start, end);
start += key.size()+1;
}
size_t actualStart = start+key.size()+1;
if(start != string::npos && (end = data.find_first_of('\n', actualStart)) != string::npos)
{
if(end != actualStart) //the found key is empty
result = data.substr(actualStart, (end-actualStart));
}
return result;
}
bool Stats::setKey(string key, string value, bool ignore_warning)
{
size_t start = 0, end = 0;
string result = "";
while((start = data.find(key, start)) != string::npos) // only check for newline at start if we have a pos > 1
{
if((start == 0 || data[start-1] == '\n') && (start+key.size() < data.size() && data[start+key.size()] == '='))
break;
//debug->notification(2, DEBUG, "SetKey(), key=%s, start=%i, end=%i", key.c_str(), start, end);
start += key.size()+1;
}
size_t actualStart = start+key.size()+1; // +1 for '='
if(start != string::npos && (end = data.find_first_of('\n', actualStart)) != string::npos)
{
//we found the key so we modify it
data.replace(actualStart, (end-actualStart), value);
return true;
}
else
{
//no occurrence is found, something is wrong
if(!ignore_warning)
debug->warning(1, DEBUG, "Could not find key \"%s\" in persona file \"%s\"", key.c_str(), path.c_str());
return false;
}
}
bool Stats::isEmpty()
{
return data.empty();
}
int Stats::loadDogtags()
{
ifstream file(dogtagPath, ifstream::in);
if(file.is_open() && file.good())
{
stringstream buffer;
buffer << file.rdbuf();
dogtags = buffer.str();
file.close();
}
else
{
dogtags = "";
debug->warning(3, DEBUG, "The dogtag file \"%s\" was not found or could not be opened, creating a new one...", dogtagPath.c_str());
ofstream dogFile(dogtagPath, ios::out | ios::trunc);
if(!dogFile.is_open())
debug->warning(2, DEBUG, "Couldn't create dogtag file for '%s'", persona.c_str());
else
dogFile.close();
}
if(dogtags.empty())
return 0;
else
{
size_t count = 0, i = 0;
while(i != string::npos)
{
i = dogtags.find("\n", i);
if(i != string::npos)
{
count++;
i++;
}
}
debug->notification(3, DEBUG, "Found %i dogtags in \"%s\"", count, dogtagPath.c_str());
return count;
}
}
Stats::dogtag Stats::getDogtag(int lineNumber)
{
int count = 0;
size_t start = 0, end = 0;
dogtag entry;
entry.data = "";
entry.id = -1;
while(count != lineNumber && start != string::npos && start < dogtags.size())
{
if(start < 0)
{
debug->warning(2, DEBUG, "getDogtag() - The while condition failed, exiting loop! count=%i start=%i dogtags.size()=%i lineNumber=%i, persona=\"%s/%s\", data=\"%s\"", count, start, (int)dogtags.size(), lineNumber, email.c_str(), persona.c_str(), dogtags.c_str());
break;
}
if((start = dogtags.find("\n", start)) != string::npos)
{
end = start;
count++;
start++;
}
}
if(end > 0)
{
start = dogtags.rfind("=", end)+1;
//if(start == string::npos)
//start = 0; //some problem with the data here, just put all data in it
entry.data = dogtags.substr(start, end-start);
if(start > 0)
end = start-1;
else
end = 0;
if((start = dogtags.rfind("\n", end)) == string::npos)
start = 0; //we are at the first line here (probably)
else
start++; //we want to have the start index after \n
entry.id = dogtags.substr(start, end-start);
debug->notification(4, DEBUG, "Got dogtag \"%s=%s\" in \"%s\", line number = %i", entry.id.c_str(), entry.data.c_str(), dogtagPath.c_str(), lineNumber);
}
else
debug->warning(2, DEBUG, "There is something wrong with the dogtags in \"%s\", line number = %i", dogtagPath.c_str(), lineNumber);
return entry;
}
void Stats::addDogtag(dogtag newDogtag)
{
string buffer = "\n";
buffer.append(newDogtag.id);
buffer.append("=");
size_t start = 0;
if((start = dogtags.find(buffer, 0)) == string::npos)
{
buffer.erase(buffer.begin());
start = dogtags.find(buffer, 0);
}
else
buffer.erase(buffer.begin()); // if we remove the \n again we don't have to change the position right?
buffer.append(newDogtag.data);
if(start != string::npos) // if we already have that id in the dogtags we only want to update it
{
//if we update a dogtag we only replace the line, newline at the end is not included
size_t end = dogtags.find("\n", start+1);
if(end == string::npos)
{
debug->warning(3, DEBUG, "dogtags data in \"%s\", seems to be corrupted, check the file, start=%i, length=%i", dogtagPath.c_str(), start, end-start);
end = start;
}
dogtags.replace(start, end-start, buffer);
debug->notification(4, DEBUG, "Replaced dogtag %s in \"%s\", start=%i, length=%i", buffer.c_str(), dogtagPath.c_str(), start, end-start);
}
else
{
buffer.append("\n"); //if we put a new dogtag we want a newline at the end
dogtags.append(buffer);
debug->notification(4, DEBUG, "Added dogtag %s to \"%s\"", buffer.c_str(), dogtagPath.c_str());
}
}
void Stats::saveDogtags()
{
string tempFile = dogtagPath;
tempFile.append(".dbk");
filesystem::path source_path(dogtagPath), dest_path(tempFile);
filesystem::copy_file(source_path, dest_path);
if(!filesystem::exists(dest_path))
return;
bool done = false;
ofstream file(dogtagPath, ofstream::out | ofstream::trunc); //we delete all content, is it safe to do this?
if(file.is_open() && file.good())
{
file.write(dogtags.c_str(), dogtags.size());
if(!file.bad())
done = true;
file.close();
debug->notification(3, DEBUG, "The dogtag file \"%s\" was saved", dogtagPath.c_str());
}
else
debug->warning(3, DEBUG, "The dogtag file \"%s\" was not found or could not be opened for saving", dogtagPath.c_str());
if(!done)
filesystem::copy_file(dest_path, source_path, filesystem::copy_option::overwrite_if_exists);
filesystem::remove(dest_path);
}
void Stats::deleteStats()
{
filesystem::path stats_path(path), dog_path(dogtagPath);
if(filesystem::remove(stats_path))
debug->notification(3, DEBUG, "Deleted file '%s'", path.c_str());
if(filesystem::remove(dog_path))
debug->notification(3, DEBUG, "Deleted file '%s'", dogtagPath.c_str());
}