geode/loader/launcher/windows/Updater.cpp

133 lines
4.2 KiB
C++
Raw Normal View History

#include <Windows.h>
#include <iostream>
#include <array>
#include <filesystem>
std::filesystem::path workingDir;
std::filesystem::path geodeDir;
std::filesystem::path updatesDir;
std::filesystem::path resourcesDir;
2023-06-10 06:57:12 -04:00
void showError(std::string const& error) {
2023-08-03 18:19:33 -04:00
MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR);
}
bool waitForFile(std::filesystem::path const& path) {
2023-08-03 18:19:33 -04:00
if (!path.has_filename())
return false;
int delay = 10;
2024-06-10 08:50:40 -04:00
int maxDelayAttempts = 20;
2023-08-03 18:19:33 -04:00
HANDLE hFile;
while ((hFile = CreateFileA(path.string().c_str(), FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_SHARING_VIOLATION) {
Sleep(delay);
2024-06-10 08:50:40 -04:00
// the delay would raise and go up to about 1 second, after which it will start a 20 second countdown
if (delay < 1024) {
2023-08-03 18:19:33 -04:00
delay *= 2;
} else {
2024-06-10 08:50:40 -04:00
maxDelayAttempts--;
// delay too long, failed too many times, just give up now
if (maxDelayAttempts == 0) {
hFile = NULL;
break;
}
}
} else {
2023-08-03 18:19:33 -04:00
break;
}
2023-08-03 18:19:33 -04:00
}
if (hFile) {
2023-08-03 18:19:33 -04:00
CloseHandle(hFile);
} else {
2023-08-03 18:19:33 -04:00
showError("Unable to update Geode: " + path.filename().string() + " is open by another process.");
return false;
}
return true;
2023-06-10 06:57:12 -04:00
}
bool updateFile(std::string const& name) {
2023-08-03 18:19:33 -04:00
std::error_code error;
if (!std::filesystem::exists(updatesDir / name, error) || error)
return true;
2023-08-03 18:19:33 -04:00
if (!waitForFile(workingDir / name))
return false;
2023-08-03 18:19:33 -04:00
std::filesystem::rename(updatesDir / name, workingDir / name, error);
if (error) {
showError("Unable to update Geode: Unable to move " + name + " - " + error.message());
return false;
2023-08-03 18:19:33 -04:00
}
return true;
2023-06-10 06:57:12 -04:00
}
void removePath(std::filesystem::path const& path) {
2023-08-03 18:19:33 -04:00
std::error_code error;
if (!std::filesystem::exists(path, error) || error)
return;
if (path.has_filename() && !waitForFile(path))
return;
if (std::filesystem::is_directory(path) && !std::filesystem::is_empty(path))
std::filesystem::remove_all(path, error);
std::filesystem::remove(path, error);
if (error) {
if (path.has_filename())
showError("Unable to update Geode: Unable to remove " + path.filename().string() + " - " + error.message());
else
showError("Unable to update Geode: Unable to remove " + path.string() + " - " + error.message());
return;
}
2023-06-10 06:57:12 -04:00
}
2023-06-10 06:57:12 -04:00
void updateResources() {
2023-08-03 18:19:33 -04:00
std::error_code error;
if (!std::filesystem::exists(updatesDir / "resources", error) || error)
return;
std::filesystem::remove_all(resourcesDir / "geode.loader", error);
if (error) {
showError("Unable to update Geode resources:" + error.message());
return;
}
std::filesystem::rename(updatesDir / "resources", resourcesDir / "geode.loader", error);
if (error) {
showError("Unable to update Geode resources: " + error.message());
return;
}
2023-06-10 06:57:12 -04:00
}
int main(int argc, char* argv[]) {
2023-08-03 18:19:33 -04:00
workingDir = std::filesystem::current_path();
geodeDir = workingDir / "geode";
updatesDir = geodeDir / "update";
resourcesDir = geodeDir / "resources";
if (std::filesystem::exists(workingDir / "GeodeBootstrapper.dll"))
removePath(workingDir / "GeodeBootstrapper.dll");
if (std::filesystem::exists(geodeDir) && std::filesystem::exists(updatesDir)) {
bool updateSuccess = true;
2024-06-02 03:36:33 -04:00
updateSuccess &= updateFile("XInput1_4.dll");
updateSuccess &= updateFile("Geode.dll");
updateSuccess &= updateFile("Geode.pdb");
2023-08-03 18:19:33 -04:00
updateResources();
// if couldnt update the files, dont delete the updates folder
if (updateSuccess)
removePath(updatesDir);
2023-08-03 18:19:33 -04:00
}
if (argc < 2)
return 0;
if (!waitForFile(workingDir / argv[1])) {
showError("There was an error restarting GD. Please, restart the game manually.");
return 0;
}
2023-08-03 18:19:33 -04:00
// restart gd using the provided path
ShellExecuteA(NULL, "open", (workingDir / argv[1]).string().c_str(), "", workingDir.string().c_str(), TRUE);
return 0;
}