add new data directory, and update updater
This commit is contained in:
@ -4,12 +4,14 @@
|
||||
#include "console.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "localized_strings.hpp"
|
||||
#include "updater.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/flags.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
|
||||
namespace filesystem
|
||||
{
|
||||
@ -39,9 +41,9 @@ namespace filesystem
|
||||
initialized = true;
|
||||
|
||||
// hardcoded paths
|
||||
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
|
||||
filesystem::register_path(L".");
|
||||
filesystem::register_path(L"h1-mod");
|
||||
filesystem::register_path(L"data");
|
||||
|
||||
// while this clears localizations, it also calls a function to load them again
|
||||
localized_strings::clear();
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "dvars.hpp"
|
||||
#include "updater.hpp"
|
||||
@ -11,11 +12,12 @@
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/http.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/http.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#define MASTER "https://master.fed0001.xyz/h1-mod/"
|
||||
@ -61,6 +63,14 @@ namespace updater
|
||||
std::string error{};
|
||||
std::string current_file{};
|
||||
std::vector<std::string> required_files{};
|
||||
std::vector<std::string> garbage_files{};
|
||||
};
|
||||
|
||||
// remove this at some point
|
||||
std::vector<std::string> old_data_files =
|
||||
{
|
||||
{"./data"},
|
||||
{"./cdata"},
|
||||
};
|
||||
|
||||
utils::concurrency::container<update_data_t> update_data;
|
||||
@ -75,6 +85,18 @@ namespace updater
|
||||
return main;
|
||||
}
|
||||
|
||||
std::string load_binary_name()
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
}
|
||||
|
||||
std::string get_binary_name()
|
||||
{
|
||||
static const auto name = load_binary_name();
|
||||
return name;
|
||||
}
|
||||
|
||||
void notify(const std::string& name)
|
||||
{
|
||||
scheduler::once([=]()
|
||||
@ -109,9 +131,22 @@ namespace updater
|
||||
bool check_file(const std::string& name, const std::string& sha)
|
||||
{
|
||||
std::string data;
|
||||
if (!utils::io::read_file(name, &data))
|
||||
|
||||
if (get_binary_name() == name)
|
||||
{
|
||||
return false;
|
||||
if (!utils::io::read_file(name, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / name).generic_string();
|
||||
if (!utils::io::read_file(path, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (utils::cryptography::sha1::compute(data, true) != sha)
|
||||
@ -122,18 +157,6 @@ namespace updater
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string load_binary_name()
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
}
|
||||
|
||||
std::string get_binary_name()
|
||||
{
|
||||
static const auto name = load_binary_name();
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_time_str()
|
||||
{
|
||||
return utils::string::va("%i", uint32_t(time(nullptr)));
|
||||
@ -144,6 +167,28 @@ namespace updater
|
||||
return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str());
|
||||
}
|
||||
|
||||
bool has_old_data_files()
|
||||
{
|
||||
bool has = false;
|
||||
for (const auto& file : old_data_files)
|
||||
{
|
||||
if (utils::io::directory_exists(file))
|
||||
{
|
||||
has = true;
|
||||
}
|
||||
}
|
||||
|
||||
return has;
|
||||
}
|
||||
|
||||
void delete_old_data_files()
|
||||
{
|
||||
for (const auto& file : old_data_files)
|
||||
{
|
||||
std::filesystem::remove_all(file);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_update_cancelled()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
@ -161,7 +206,16 @@ namespace updater
|
||||
return false;
|
||||
}
|
||||
|
||||
return utils::io::write_file(name, data);
|
||||
if (get_binary_name() == name)
|
||||
{
|
||||
return utils::io::write_file(name, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / name).generic_string();
|
||||
return utils::io::write_file(path, data);
|
||||
}
|
||||
}
|
||||
|
||||
void delete_old_file()
|
||||
@ -177,6 +231,56 @@ namespace updater
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::string> find_garbage_files(const std::vector<std::string>& update_files)
|
||||
{
|
||||
std::vector<std::string> garbage_files{};
|
||||
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / CLIENT_DATA_FOLDER).generic_string();
|
||||
if (!utils::io::directory_exists(path))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto current_files = utils::io::list_files_recursively(path);
|
||||
for (const auto& file : current_files)
|
||||
{
|
||||
bool found = false;
|
||||
for (const auto& update_file : update_files)
|
||||
{
|
||||
const auto update_file_ = (appdata_folder / update_file).generic_string();
|
||||
const auto path_a = std::filesystem::path(file);
|
||||
const auto path_b = std::filesystem::path(update_file_);
|
||||
const auto is_directory = utils::io::directory_exists(file);
|
||||
const auto compare = path_a.compare(path_b);
|
||||
|
||||
if ((is_directory && compare == -1) || compare == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
console::info("[Updater] Found extra file %s\n", file.data());
|
||||
#endif
|
||||
if (file.ends_with(".ff"))
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_.restart_required = true;
|
||||
});
|
||||
}
|
||||
|
||||
garbage_files.push_back(file);
|
||||
}
|
||||
}
|
||||
|
||||
return garbage_files;
|
||||
}
|
||||
|
||||
std::string get_mode_flag()
|
||||
{
|
||||
if (game::environment::is_mp())
|
||||
@ -199,36 +303,11 @@ namespace updater
|
||||
}
|
||||
}
|
||||
|
||||
// workaround
|
||||
void relaunch()
|
||||
{
|
||||
if (!utils::io::file_exists(BINARY_NAME))
|
||||
{
|
||||
utils::nt::terminate(0);
|
||||
return;
|
||||
}
|
||||
|
||||
STARTUPINFOA startup_info;
|
||||
PROCESS_INFORMATION process_info;
|
||||
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
ZeroMemory(&process_info, sizeof(process_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
|
||||
char current_dir[MAX_PATH];
|
||||
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
|
||||
|
||||
char buf[1024] = {0};
|
||||
const auto command_line = utils::string::va("%s %s", GetCommandLineA(), get_mode_flag().data());
|
||||
strcpy_s(buf, 1024, command_line);
|
||||
|
||||
CreateProcess(BINARY_NAME, buf, nullptr, nullptr, false, NULL, nullptr, current_dir,
|
||||
&startup_info, &process_info);
|
||||
|
||||
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
|
||||
if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess);
|
||||
|
||||
utils::nt::terminate(0);
|
||||
const auto mode = game::environment::is_mp() ? "-multiplayer" : "-singleplayer";
|
||||
utils::nt::relaunch_self(mode);
|
||||
utils::nt::terminate();
|
||||
}
|
||||
|
||||
void set_has_tried_update(bool tried)
|
||||
@ -282,7 +361,7 @@ namespace updater
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.required_files.size() > 0;
|
||||
return data_.required_files.size() > 0 || data_.garbage_files.size() > 0 || has_old_data_files();
|
||||
});
|
||||
}
|
||||
|
||||
@ -312,9 +391,7 @@ namespace updater
|
||||
|
||||
void cancel_update()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] Cancelling update\n");
|
||||
#endif
|
||||
console::debug("[Updater] Cancelling update\n");
|
||||
|
||||
return update_data.access([](update_data_t& data_)
|
||||
{
|
||||
@ -327,9 +404,7 @@ namespace updater
|
||||
cancel_update();
|
||||
reset_data();
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] starting update check\n");
|
||||
#endif
|
||||
console::debug("[Updater] starting update check\n");
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
@ -365,6 +440,7 @@ namespace updater
|
||||
}
|
||||
|
||||
std::vector<std::string> required_files;
|
||||
std::vector<std::string> update_files;
|
||||
|
||||
const auto files = j.GetArray();
|
||||
for (const auto& file : files)
|
||||
@ -377,6 +453,8 @@ namespace updater
|
||||
const auto name = file[0].GetString();
|
||||
const auto sha = file[2].GetString();
|
||||
|
||||
update_files.push_back(name);
|
||||
|
||||
if (!check_file(name, sha))
|
||||
{
|
||||
if (get_binary_name() == name)
|
||||
@ -387,19 +465,29 @@ namespace updater
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] need file %s\n", name);
|
||||
#endif
|
||||
std::string name_ = name;
|
||||
if (name_.ends_with(".ff"))
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_.restart_required = true;
|
||||
});
|
||||
}
|
||||
|
||||
console::debug("[Updater] need file %s\n", name);
|
||||
|
||||
required_files.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
update_data.access([&required_files](update_data_t& data_)
|
||||
const auto garbage_files = find_garbage_files(update_files);
|
||||
|
||||
update_data.access([&](update_data_t& data_)
|
||||
{
|
||||
data_.check.done = true;
|
||||
data_.check.success = true;
|
||||
data_.required_files = required_files;
|
||||
data_.garbage_files = garbage_files;
|
||||
});
|
||||
|
||||
notify("update_check_done");
|
||||
@ -408,15 +496,32 @@ namespace updater
|
||||
|
||||
void start_update_download()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] starting update download\n");
|
||||
#endif
|
||||
console::debug("[Updater] starting update download\n");
|
||||
|
||||
if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
delete_old_data_files();
|
||||
|
||||
const auto garbage_files = update_data.access<std::vector<std::string>>([](update_data_t& data_)
|
||||
{
|
||||
return data_.garbage_files;
|
||||
});
|
||||
|
||||
for (const auto& file : garbage_files)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(file);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
console::error("Failed to delete %s\n", file.data());
|
||||
}
|
||||
}
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
const auto required_files = update_data.access<std::vector<std::string>>([](update_data_t& data_)
|
||||
@ -433,9 +538,7 @@ namespace updater
|
||||
data_.current_file = file;
|
||||
});
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[Updater] downloading file %s\n", file.data());
|
||||
#endif
|
||||
console::debug("[Updater] downloading file %s\n", file.data());
|
||||
|
||||
const auto data = download_file(file);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define CLIENT_DATA_FOLDER "cdata"
|
||||
|
||||
namespace updater
|
||||
{
|
||||
void relaunch();
|
||||
|
Reference in New Issue
Block a user