Skip to content

Commit

Permalink
Merge pull request #30 from mgziminsky/master
Browse files Browse the repository at this point in the history
Save manager improvements
  • Loading branch information
SalamatiQus authored Aug 26, 2019
2 parents 250c95c + f0268e8 commit 7b2581a
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 113 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
*.sdf
*.user
*.opensdf
Release
.vs
Release
Debug
*.suo
*.opendb
*.filters
2 changes: 2 additions & 0 deletions Actions.def
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ ACTION(userTrigger, SDLOG(0, "==================================================
ACTION(reloadHUDVertices, RSManager::get().reloadHudVertices());

ACTION(togglePaused, RSManager::get().togglePaused());

ACTION(manualBackup, SaveManager::get().backup(););
2 changes: 2 additions & 0 deletions DATA/DSfixKeys.ini
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ toggle30FPSLimit VK_BACK
#userTrigger VK_F1
#togglePaused VK_F9

manualBackup VK_F12

# Available Actions:
# toggleCursorVisibility, toggleCursorCapture, toggleBorderlessFullscreen, takeHudlessScreenshot, toggleHUD,
# toggleSMAA, toggleVSSAO, toggleDofGauss, toggleHudChange, reloadSSAOEffect, singleFrameFullCapture, userTrigger
Expand Down
1 change: 1 addition & 0 deletions KeyActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ using namespace std;
#include "WindowManager.h"
#include "Settings.h"
#include "RenderstateManager.h"
#include "SaveManager.h"

KeyActions KeyActions::instance;

Expand Down
247 changes: 141 additions & 106 deletions SaveManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "SaveManager.h"

#include <algorithm>
#include <functional>

#include "Settings.h"

Expand All @@ -10,127 +11,161 @@
#define TIMESTAMP_LENGTH 12
#define TIMESTAMP_LENGTH_STR EXPAND_AND_QUOTE(TIMESTAMP_LENGTH)

#define SAVE_EXT ".sl2"
#define BACKUP_EXT ".bak"

string getFileNameFromPath(const string& path) {
size_t pos = path.rfind('\\');
if (pos != path.npos) {
return path.substr(pos + 1);
}
else {
SDLOG(0, "ERROR: SaveManager could not extract file name from path %s\n", path.c_str());
}
return path;
}

bool operator>(const FILETIME& lhs, const FILETIME& rhs) {
ULARGE_INTEGER uiL, uiR;

uiL.LowPart = lhs.dwLowDateTime;
uiL.HighPart = lhs.dwHighDateTime;

uiR.LowPart = rhs.dwLowDateTime;
uiR.HighPart = rhs.dwHighDateTime;

return uiL.QuadPart > uiR.QuadPart;
}

bool fileDataWriteTimeCompareGreater(const WIN32_FIND_DATA& lhs, const WIN32_FIND_DATA& rhs) {
return lhs.ftLastWriteTime > rhs.ftLastWriteTime;
}

time_t fileTimeToEpoch(const FILETIME& ft) {
ULARGE_INTEGER ull;
ull.LowPart = ft.dwLowDateTime;
ull.HighPart = ft.dwHighDateTime;

return ull.QuadPart / 10000000ULL - 11644473600ULL;
}

string joinPath(const string& base, const string& comp) {
char buffer[MAX_PATH];
sprintf_s(buffer, "%s\\%s", base.c_str(), comp.c_str());
return string(buffer);
}

SaveManager SaveManager::instance;

void SaveManager::init() {
if(Settings::get().getEnableBackups()) {
CHAR documents[MAX_PATH];
HRESULT hr = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
char buffer[MAX_PATH];
sprintf_s(buffer, "%s%s", documents, "\\NBGI\\DarkSouls\\*");

// find user save folder
WIN32_FIND_DATA userSaveFolderData;
HANDLE searchHandle = FindFirstFile(buffer, &userSaveFolderData);
bool found = false;
if(searchHandle != INVALID_HANDLE_VALUE) {
do {
std::string fn = userSaveFolderData.cFileName;
bool dir = userSaveFolderData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
bool saveFile = fn.substr(fn.find_last_of(".") + 1) == "sl2";
// newer versions don't contain an additional folder under NBGI\\DarkSouls
if (fn.size() > 2 && (dir || saveFile)) {
if (dir)
sprintf_s(buffer, "%s%s%s", documents, "\\NBGI\\DarkSouls\\", userSaveFolderData.cFileName);
else
sprintf_s(buffer, "%s%s", documents, "\\NBGI\\DarkSouls");
userSaveFolder = string(buffer);
SDLOG(0, "SaveManager: user save folder is %s\n", userSaveFolder.c_str());
found = true;
break;
}
} while(FindNextFile(searchHandle, &userSaveFolderData));
}
if(!found) {
SDLOG(0, "SaveManager: could not determine user save folder\n");
return;
}

removeOldBackups();
}
if (Settings::get().getEnableBackups()) {
char documents[MAX_PATH];
HRESULT hr = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);

if (hr == S_OK)
{
userSaveFolder = joinPath(documents, "NBGI\\DarkSouls");
SDLOG(0, "SaveManager: Found save folder at %s\n", userSaveFolder);
removeOldBackups();
}
}
}

void SaveManager::tick() {
if(Settings::get().getEnableBackups()) {
time_t curTime = time(NULL);
if(curTime - getLastBackupTime() > Settings::get().getBackupInterval()) {
backup(curTime);
lastBackupTime = curTime;
}
}
if (Settings::get().getEnableBackups() && !userSaveFolder.empty()) {
time_t ls, curTime = time(NULL);
time_t backupInterval = Settings::get().getBackupInterval();
if (curTime - getLastBackupTime() > backupInterval &&
getLastSaveTime() - getLastBackupSaveTime() > backupInterval) {
SDLOG(2, "SaveManager: last backup time %ld\n", lastBackupTime);
SDLOG(2, "SaveManager: last backup save time %ld\n", lastBackupSaveTime);
backup();
}
}
}

time_t SaveManager::getLastBackupTime() {
if(lastBackupTime == 0) {
vector<string> backupFiles = getSaveFiles(".bak");
if(!backupFiles.empty()) {
string fn = getFileNameFromPath(backupFiles.front());
sscanf_s(fn.c_str(), "%lu", &lastBackupTime);
}
}
SDLOG(3, "SaveManager: last backup time %ld\n", lastBackupTime);
return lastBackupTime;
if (lastBackupTime == 0) {
vector<WIN32_FIND_DATA> backupFiles = getSaveFiles(BACKUP_EXT);
if (!backupFiles.empty()) {
lastBackupTime = lastBackupSaveTime = fileTimeToEpoch(backupFiles[0].ftLastWriteTime);
}
}
return lastBackupTime;
}

vector<string> SaveManager::getSaveFiles(const char* ending /*= ".sl2"*/) {
SDLOG(2, "SaveManager: searching for files ending on %s\n", ending);
vector<string> ret;
// find saved files
if(userSaveFolder.length() > 0) {
char buffer[MAX_PATH];
sprintf_s(buffer, "%s\\*%s", userSaveFolder.c_str(), ending);
WIN32_FIND_DATA saveFileData;
HANDLE searchHandle = FindFirstFile(buffer, &saveFileData);
if(searchHandle != INVALID_HANDLE_VALUE) {
do {
char buff2[MAX_PATH];
sprintf_s(buff2, "%s\\%s", userSaveFolder.c_str(), saveFileData.cFileName);
ret.push_back(string(buff2));
} while(FindNextFile(searchHandle, &saveFileData));
}
std::sort(ret.begin(), ret.end());
std::reverse(ret.begin(), ret.end());
for(size_t i=0; i<ret.size(); ++i) {
SDLOG(4, "SaveManager: found existing file %s\n", ret[i].c_str());
}
}
return ret;
time_t SaveManager::getLastBackupSaveTime()
{
if (lastBackupSaveTime == 0) {
vector<WIN32_FIND_DATA> backupFiles = getSaveFiles(BACKUP_EXT);
if (!backupFiles.empty()) {
lastBackupSaveTime = fileTimeToEpoch(backupFiles[0].ftLastWriteTime);
}
}
return lastBackupSaveTime;
}

void SaveManager::backup(const time_t curTime) {
SDLOG(1, "SaveManager: Backing up save files\n");
char buffer[MAX_PATH];
vector<string> saveFiles = getSaveFiles();
for(size_t i=0; i<saveFiles.size(); ++i) {
string fn = getFileNameFromPath(saveFiles[i]);
sprintf_s(buffer, "%s\\%0" TIMESTAMP_LENGTH_STR "lu_", userSaveFolder.c_str(), curTime);
string newPath = string(buffer) + fn + ".bak";
if(CopyFile(saveFiles[i].c_str(), newPath.c_str(), false) == 0) {
SDLOG(0, "ERROR: SaveManager failed to back up file! (Copying %s to %s)\n", saveFiles[i].c_str(), buffer);
} else {
SDLOG(1, "SaveManager: Backed up %s\n", fn.c_str());
}
}
removeOldBackups();
time_t SaveManager::getLastSaveTime()
{
vector<WIN32_FIND_DATA> saveFiles = getSaveFiles(SAVE_EXT);
return saveFiles.empty() ? 0 : fileTimeToEpoch(saveFiles[0].ftLastWriteTime);
}

void SaveManager::removeOldBackups() {
vector<string> backupFiles = getSaveFiles(".bak");
if(Settings::get().getMaxBackups() < backupFiles.size()) {
SDLOG(1, "SaveManager: Removing %u old backups\n", backupFiles.size() - Settings::get().getMaxBackups());
for(size_t i=Settings::get().getMaxBackups(); i<backupFiles.size(); ++i) {
DeleteFile(backupFiles[i].c_str());
}
}
vector<WIN32_FIND_DATA> SaveManager::getSaveFiles(const char* ending) {
vector<WIN32_FIND_DATA> ret;

if (!userSaveFolder.empty()) {
SDLOG(4, "SaveManager: searching for files ending with %s\n", ending);

char buffer[MAX_PATH];
sprintf_s(buffer, "%s\\*%s", userSaveFolder.c_str(), ending);

WIN32_FIND_DATA saveFileData;
HANDLE sh = FindFirstFile(buffer, &saveFileData);
if (sh != INVALID_HANDLE_VALUE)
{
do
{
ret.push_back(saveFileData);
SDLOG(3, "SaveManager: found save file %s\\%s\n", userSaveFolder.c_str(), saveFileData.cFileName);
} while (FindNextFile(sh, &saveFileData));
std::sort(ret.begin(), ret.end(), fileDataWriteTimeCompareGreater);
}
}
return ret;
}

string SaveManager::getFileNameFromPath(const string& path) {
size_t pos = path.rfind('\\');
if(pos != path.npos) {
pos += 1;
return path.substr(pos);
} else {
SDLOG(0, "ERROR: SaveManager could not extract file name from path %s\n", path.c_str());
}
return path;
void SaveManager::backup() {
SDLOG(3, "SaveManager: Backing up save files\n");

vector<WIN32_FIND_DATA> saveFiles = getSaveFiles(SAVE_EXT);

if (!saveFiles.empty()) {
WIN32_FIND_DATA saveFile = saveFiles[0];
string saveFullPath = joinPath(userSaveFolder, saveFile.cFileName);

char newPath[MAX_PATH];
time_t curTime = time(NULL);
sprintf_s(newPath, "%s\\%0" TIMESTAMP_LENGTH_STR "llu_%s" BACKUP_EXT, userSaveFolder.c_str(), curTime, saveFile.cFileName);

if (CopyFile(saveFullPath.c_str(), newPath, false) == 0) {
SDLOG(0, "ERROR: SaveManager failed to back up file! (Copying %s to %s)\n", saveFullPath.c_str(), newPath);
}
else {
SDLOG(1, "SaveManager: Backed up %s to %s\n", saveFullPath.c_str(), newPath);
lastBackupTime = curTime;
lastBackupSaveTime = fileTimeToEpoch(saveFile.ftLastWriteTime);
removeOldBackups();
}
}
}

void SaveManager::removeOldBackups() {
vector<WIN32_FIND_DATA> backupFiles = getSaveFiles(BACKUP_EXT);
if (Settings::get().getMaxBackups() < backupFiles.size()) {
SDLOG(1, "SaveManager: Removing %u old backups\n", backupFiles.size() - Settings::get().getMaxBackups());
for (size_t i = Settings::get().getMaxBackups(); i < backupFiles.size(); ++i) {
DeleteFile(joinPath(userSaveFolder, backupFiles[i].cFileName).c_str());
}
}
}
14 changes: 8 additions & 6 deletions SaveManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ using std::string;

class SaveManager {
static SaveManager instance;

string userSaveFolder;
time_t lastBackupTime;
time_t lastBackupTime;
time_t lastBackupSaveTime;

vector<WIN32_FIND_DATA> getSaveFiles(const char* ending);

string getFileNameFromPath(const string& path);
vector<string> getSaveFiles(const char* ending = ".sl2");

void backup(const time_t curTime);
void removeOldBackups();

time_t getLastBackupTime();
time_t getLastBackupSaveTime();
time_t getLastSaveTime();

public:
static SaveManager& get() {
Expand All @@ -35,5 +36,6 @@ class SaveManager {

void init();
void tick();
void backup();
};

0 comments on commit 7b2581a

Please sign in to comment.