diff --git a/src/unlocker/cachecleaner.cpp b/src/unlocker/cachecleaner.cpp new file mode 100644 index 0000000..63e7f92 --- /dev/null +++ b/src/unlocker/cachecleaner.cpp @@ -0,0 +1,128 @@ +#include "cachecleaner.h" + +#include + +#include +#include + +#include +#include + +CacheCleaner::CacheCleaner() : _running(false), _monitorThread(nullptr) {} + +CacheCleaner::~CacheCleaner() +{ + shutdown(); +} + +void CacheCleaner::init() +{ + std::string localAppData = getLocalAppDataPath(); + if (localAppData == "") return Log::error("Failed to get LocalAppData?"); + + _cacheDir = localAppData + "\\DeadByDaylight\\Saved\\PersistentDownloadDir"; + + // this is pointless but just in case + std::filesystem::create_directories(_cacheDir); + + clearFolder(_cacheDir); + + _running = true; + //_monitorThread = std::make_unique(&CacheCleaner::monitorLoop, this); +} + +void CacheCleaner::shutdown() +{ + if (!_running) return; + _running = false; + + if (_monitorThread && _monitorThread->joinable()) _monitorThread->join(); +} + +std::string CacheCleaner::getLocalAppDataPath() +{ + char buffer[MAX_PATH]; + if (SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, buffer) == S_OK) + { + return std::string(buffer); + } + return ""; +} + +void CacheCleaner::clearFolder(std::string& path) +{ + try + { + for (const auto& entry : std::filesystem::directory_iterator(path)) + { + std::filesystem::remove_all(entry.path()); + } + } + catch (...) + { + } +} + +void CacheCleaner::monitorLoop() +{ + HANDLE changeHandle = FindFirstChangeNotificationA(_cacheDir.c_str(), TRUE, + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_LAST_WRITE); + + if (changeHandle == INVALID_HANDLE_VALUE) + { + Log::error("Failed to create change notification"); + _running = false; + return; + } + + Log::verbose("Cache cleaner monitoring started"); + + std::unordered_set previousPids; + + while (_running) + { + // Wait 2 seconds between checks + for (int i = 0; i < 20 && _running; i++) + Sleep(100); + + if (!_running) break; + + // Take snapshot and check for new processes in one pass + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) continue; + + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + + std::unordered_set currentPids; + + if (Process32First(hSnapshot, &pe32)) + { + do + { + DWORD pid = pe32.th32ProcessID; + currentPids.insert(pid); + + if (previousPids.find(pid) == previousPids.end()) + { + std::string processName(pe32.szExeFile); + + for (char& c : processName) + c = static_cast(tolower(c)); + + if (processName.find("deadbydaylight") != std::string::npos) + { + Log::verbose("New DeadByDaylight process detected (PID: {}), clearing cache", pid); + clearFolder(_cacheDir); + } + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + previousPids = std::move(currentPids); + } + + FindCloseChangeNotification(changeHandle); +} diff --git a/src/unlocker/cachecleaner.h b/src/unlocker/cachecleaner.h new file mode 100644 index 0000000..72b8344 --- /dev/null +++ b/src/unlocker/cachecleaner.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +class CacheCleaner +{ + public: + CacheCleaner(); + ~CacheCleaner(); + + void init(); + void shutdown(); + + private: + std::string getLocalAppDataPath(); + void clearFolder(std::string& path); + void monitorLoop(); + + std::atomic _running; + std::unique_ptr _monitorThread; + std::string _cacheDir; +};