add new data directory, and update updater

This commit is contained in:
m 2022-09-03 06:00:31 -05:00
parent 315630bb76
commit e912552b4c
34 changed files with 286 additions and 265 deletions

View File

@ -0,0 +1,13 @@
local mod_eula = function(unk1, unk2)
return LUI.EULABase.new(CoD.CreateState(0, 0, 0, 0, CoD.AnchorTypes.All), {
textStrings = LUI.EULABase.CreateTextStrings("@CUSTOM_DEPOT_EULA_", 6),
declineCallback = function(unk3)
unk2.declineCallback(unk3)
end,
acceptCallback = function(unk4)
unk2.acceptCallback(unk4)
end
})
end
LUI.MenuBuilder.registerPopupType("mod_eula", mod_eula)

View File

@ -1,16 +1,5 @@
local pcdisplay = luiglobals.require("LUI.PCDisplay") local pcdisplay = luiglobals.require("LUI.PCDisplay")
game:addlocalizedstring("LUA_MENU_FPS", "FPS Counter")
game:addlocalizedstring("LUA_MENU_FPS_DESC", "Show FPS Counter.")
game:addlocalizedstring("LUA_MENU_LATENCY", "Server Latency")
game:addlocalizedstring("LUA_MENU_LATENCY_DESC", "Show server latency.")
game:addlocalizedstring("LUA_MENU_RED_DOT_BRIGHTNESS", "Red dot Brightness")
game:addlocalizedstring("LUA_MENU_RED_DOT_BRIGHTNESS_DESC", "Adjust the brightness of red dot reticles.")
game:addlocalizedstring("MENU_SYSINFO_CUSTOMER_SUPPORT_URL", "https://h1.gg/")
function createdivider(menu, text) function createdivider(menu, text)
local element = LUI.UIElement.new({ local element = LUI.UIElement.new({
leftAnchor = true, leftAnchor = true,

View File

@ -1,12 +1,3 @@
game:addlocalizedstring("MENU_MODS", "MODS")
game:addlocalizedstring("MENU_MODS_DESC", "Load installed mods.")
game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.")
game:addlocalizedstring("LUA_MENU_MOD_DESC", "&&1\nAuthor: &&2\nVersion: &&3")
game:addlocalizedstring("LUA_MENU_LOADED_MOD", "Loaded mod: ^2&&1")
game:addlocalizedstring("LUA_MENU_AVAILABLE_MODS", "Available mods")
game:addlocalizedstring("LUA_MENU_UNLOAD", "Unload")
game:addlocalizedstring("LUA_MENU_UNLOAD_DESC", "Unload the currently loaded mod.")
function createdivider(menu, text) function createdivider(menu, text)
local element = LUI.UIElement.new({ local element = LUI.UIElement.new({
leftAnchor = true, leftAnchor = true,
@ -52,7 +43,6 @@ end
function getmodname(path) function getmodname(path)
local name = path local name = path
game:addlocalizedstring(name, name) game:addlocalizedstring(name, name)
game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.")
local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", name) local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", name)
local infofile = path .. "/info.json" local infofile = path .. "/info.json"

View File

@ -1,8 +1,5 @@
LUI.MenuBuilder.registerPopupType("ShaderCacheDialog_original", LUI.ShaderCacheDialog.new) LUI.MenuBuilder.registerPopupType("ShaderCacheDialog_original", LUI.ShaderCacheDialog.new)
game:addlocalizedstring("PLATFORM_SHADER_PRECACHE_ASK", "Would you like to populate the shader cache? It may cause crashes with certain GPUs (e.g. RTX cards) but will improve performance if successful.")
game:addlocalizedstring("MENU_NO_DONT_ASK", "No, don't ask me again")
local function dialog(...) local function dialog(...)
if (game:sharedget("has_accepted_shader_caching") == "1") then if (game:sharedget("has_accepted_shader_caching") == "1") then
return LUI.ShaderCacheDialog.new(...) return LUI.ShaderCacheDialog.new(...)

View File

@ -1,8 +1,6 @@
local Lobby = luiglobals.Lobby local Lobby = luiglobals.Lobby
local MPLobbyOnline = LUI.mp_menus.MPLobbyOnline local MPLobbyOnline = LUI.mp_menus.MPLobbyOnline
game:addlocalizedstring("LUA_MENU_SERVERLIST", "SERVER LIST")
function LeaveLobby(f5_arg0) function LeaveLobby(f5_arg0)
LeaveXboxLive() LeaveXboxLive()
if Lobby.IsInPrivateParty() == false or Lobby.IsPrivatePartyHost() then if Lobby.IsInPrivateParty() == false or Lobby.IsPrivatePartyHost() then

View File

@ -5,11 +5,6 @@ if (not SystemLinkJoinMenu) then
return return
end end
game:addlocalizedstring("MENU_NUMPLAYERS", "Players")
game:addlocalizedstring("MENU_PING", "Ping")
game:addlocalizedstring("SERVERLIST_PLAYER_COUNT", "&&1 Players")
game:addlocalizedstring("SERVERLIST_SERVER_COUNT", "&&1 Servers")
local columns = { local columns = {
{ {
offset = 40, offset = 40,

View File

@ -2,32 +2,6 @@ if (game:issingleplayer() or not Engine.InFrontend()) then
return return
end end
game:addlocalizedstring("LUA_MENU_STATS", "Stats")
game:addlocalizedstring("LUA_MENU_STATS_DESC", "Edit player stats settings.")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS", "Unlock all items")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_ITEMS_DESC",
"Whether items should be locked based on the player's stats or always unlocked.")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_LOOT", "Unlock all loot")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_LOOT_DESC",
"Whether loot should be locked based on the player's stats or always unlocked.")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES", "Unlock all classes")
game:addlocalizedstring("LUA_MENU_UNLOCKALL_CLASSES_DESC",
"Whether classes should be locked based on the player's stats or always unlocked.")
game:addlocalizedstring("LUA_MENU_PRESTIGE", "Prestige")
game:addlocalizedstring("LUA_MENU_PRESTIGE_DESC", "Edit prestige level.")
game:addlocalizedstring("LUA_MENU_RANK", "Rank")
game:addlocalizedstring("LUA_MENU_RANK_DESC", "Edit rank.")
game:addlocalizedstring("LUA_MENU_UNSAVED_CHANGES", "You have unsaved changes, are you sure you want to exit?")
game:addlocalizedstring("LUA_MENU_SAVE", "Save changes")
game:addlocalizedstring("LUA_MENU_SAVE_DESC", "Save changes.")
game:addlocalizedstring("LUA_MENU_SETTINGS", "Settings")
game:addlocalizedstring("LUA_MENU_EDIT_STATS", "Edit Stats")
function createdivider(menu, text) function createdivider(menu, text)
local element = LUI.UIElement.new({ local element = LUI.UIElement.new({
leftAnchor = true, leftAnchor = true,

View File

@ -1,117 +0,0 @@
-- modified version of https://github.com/Joelrau/S1x-IW6x-g_log-script (permission to use by author)
if (game:getdvar("gamemode") ~= "mp") then
return
end
-- setup dvars
game:setdvarifuninitialized("logfile", 1)
if (tonumber(game:getdvar("logfile")) < 1) then
return
end
game:setdvarifuninitialized("g_log", "logs/games_mp.log")
start_time = 0
function get_time()
local seconds = math.floor((game:gettime() - start_time) / 1000)
local minutes = math.floor(seconds / 60)
time = string.format("%d:%02d", minutes, seconds - minutes * 60)
while (string.len(time) < 6) do
time = " " .. time
end
time = time .. " "
return time
end
function create_path(path)
local dir = path:gsub("%/", "\\"):match("(.*[\\])")
os.execute("if not exist " .. dir .. " mkdir " .. dir)
end
function log_print(message)
local path = game:getdvar("g_log")
local file = io.open(path, "a")
if (file == nil) then
create_path(path)
file = assert(io.open(path, "a"))
end
file:write(get_time() .. message .. "\n")
file:close()
end
function init()
start_time = game:gettime()
log_print("------------------------------------------------------------")
log_print("InitGame")
-- player callbacks
level:onnotify("connected", function(player)
player:player_connected()
end)
level:onnotify("say", function(player, message, hidden)
player:say(message)
end)
level:onnotify("say_team", function(player, message, hidden)
player:say(message, "say_team")
end)
-- damage/killed hooks
game:onplayerdamage(player_damage)
game:onplayerkilled(player_killed)
-- other level notifies for log
level:onnotify("exitLevel_called", function()
log_print("ExitLevel: executed")
end)
level:onnotify("shutdownGame_called", function()
log_print("ShutdownGame:")
log_print("------------------------------------------------------------")
end)
end
function entity:player_connected()
log_print(string.format("J;%s;%i;%s", self:getguid(), self:getentitynumber(), self.name))
self:onnotifyonce("disconnect", function()
self:disconnect()
end)
end
function entity:disconnect()
log_print(string.format("Q;%s;%i;%s", self:getguid(), self:getentitynumber(), self.name))
end
function player_damage(self_, inflictor, attacker, damage, dflags, mod, weapon, vPoint, vDir, hitLoc)
if (game:isplayer(attacker) == 1) then
log_print(string.format("D;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(),
self_.team, self_.name, attacker:getguid(), attacker:getentitynumber(), attacker.team, attacker.name,
weapon, damage, mod, hitLoc))
else
log_print(string.format("D;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(),
self_.team, self_.name, "", "-1", "world", "", weapon, damage, mod, hitLoc))
end
end
function player_killed(self_, inflictor, attacker, damage, mod, weapon, vDir, hitLoc, psTimeOffset, deathAnimDuration)
if (game:isplayer(attacker) == 1) then
log_print(string.format("K;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(),
self_.team, self_.name, attacker:getguid(), attacker:getentitynumber(), attacker.team, attacker.name,
weapon, damage, mod, hitLoc))
else
log_print(string.format("K;%s;%i;%s;%s;%s;%i;%s;%s;%s;%i;%s;%s", self_:getguid(), self_:getentitynumber(),
self_.team, self_.name, "", "-1", "world", "", weapon, damage, mod, hitLoc))
end
end
-- this function handles 'say' and 'say_team'
function entity:say(message, mode)
if (not mode) then
mode = "say"
end
log_print(string.format("%s;%s;%i;%s;%s", mode, self:getguid(), self:getentitynumber(), self.name, message))
end
init()

View File

@ -1,23 +0,0 @@
game:addlocalizedstring("CUSTOM_DEPOT_EULA_1", "Dear User,")
game:addlocalizedstring("CUSTOM_DEPOT_EULA_2",
"By using this feature, you acknowledge that you are over 18 years old, and that any sort of chance games / gambling are allowed in your country (even if they do not involve real money).")
game:addlocalizedstring("CUSTOM_DEPOT_EULA_3",
"The H1-Mod team is not responsible if you break the law within your country, and the sole responsibility will be upon you to respect the same.")
game:addlocalizedstring("CUSTOM_DEPOT_EULA_4",
"The H1-Mod team will never include real money transactions within the modified systems. The only way to get currency, should you wish to, is by playing the game.")
game:addlocalizedstring("CUSTOM_DEPOT_EULA_5", "Best Regards,")
game:addlocalizedstring("CUSTOM_DEPOT_EULA_6", "The H1-Mod Team.")
local mod_eula = function(unk1, unk2)
return LUI.EULABase.new(CoD.CreateState(0, 0, 0, 0, CoD.AnchorTypes.All), {
textStrings = LUI.EULABase.CreateTextStrings("@CUSTOM_DEPOT_EULA_", 6),
declineCallback = function(unk3)
unk2.declineCallback(unk3)
end,
acceptCallback = function(unk4)
unk2.acceptCallback(unk4)
end
})
end
LUI.MenuBuilder.registerPopupType("mod_eula", mod_eula)

View File

@ -1 +0,0 @@
-- this patch has been moved to ui_scripts/patches/gamemodes.lua

View File

@ -1 +0,0 @@
-- this patch has been moved to ui_scripts/patches/no_mode_switch.lua

View File

@ -0,0 +1 @@
localize,english
1 localize english

View File

@ -0,0 +1 @@
build,eng_h1_mod_common
1 build eng_h1_mod_common

View File

@ -0,0 +1,53 @@
{
"CUSTOM_DEPOT_EULA_1": "Dear User,",
"CUSTOM_DEPOT_EULA_2": "By using this feature, you acknowledge that you are over the age of 18 years old, and that any sort of gambling is allowed in your country. (even if they do not involve real money)",
"CUSTOM_DEPOT_EULA_3": "The H1-mod team is not responsible if you break any law within your country, and the sole responsibility will be upon you to respect the same.",
"CUSTOM_DEPOT_EULA_4": "The H1-mod team will never include real money transactions within the modified systems. The only way to get currency, should you wish to, is by playing the game.",
"CUSTOM_DEPOT_EULA_5": "Best regards,",
"CUSTOM_DEPOT_EULA_6": "The H1-mod team.",
"LUA_MENU_FPS": "FPS Counter",
"LUA_MENU_FPS_DESC": "Show FPS counter.",
"LUA_MENU_LATENCY": "Server Latency",
"LUA_MENU_LATENCY_DESC": "Show server latency.",
"LUA_MENU_RED_DOT_BRIGHTNESS": "Red Dot Brightness",
"LUA_MENU_RED_DOT_BRIGHTNESS_DESC": "Adjust the brightness of red dot reticles.",
"MENU_SYSINFO_CUSTOMER_SUPPORT_URL": "https://h1.gg/",
"MENU_MODS": "MODS",
"MENU_MODS_DESC": "Load installed mods.",
"LUA_MENU_MOD_DESC_DEFAULT": "Load &&1.",
"LUA_MENU_MOD_DESC": "&&1\nAuthor: &&2\nVersion: &&3",
"LUA_MENU_LOADED_MOD": "Loaded mod: ^2&&1",
"LUA_MENU_AVAILABLE_MODS": "Available mods",
"LUA_MENU_UNLOAD": "Unload",
"LUA_MENU_UNLOAD_DESC": "Unload the currently loaded mod.",
"PLATFORM_SHADER_PRECACHE_ASK": "Would you like to populate the shader cache? It may cause crashes with certain GPUs (e.g. RTX cards) but will improve performance if successful.",
"MENU_NO_DONT_ASK": "No, don't ask me again",
"LUA_MENU_SERVERLIST": "SERVER LIST",
"MENU_NUMPLAYERS": "Players",
"MENU_PING": "Ping",
"SERVERLIST_PLAYER_COUNT": "&&1 Players",
"SERVERLIST_SERVER_COUNT": "&&1 Servers",
"LUA_MENU_STATS": "Stats",
"LUA_MENU_STATS_DESC": "Edit player stats settings.",
"LUA_MENU_UNLOCKALL_ITEMS": "Unlock all items",
"LUA_MENU_UNLOCKALL_ITEMS_DESC": "Whether items should be locked based on the player's stats or always unlocked.",
"LUA_MENU_UNLOCKALL_LOOT": "Unlock all loot",
"LUA_MENU_UNLOCKALL_LOOT_DESC": "Whether loot should be locked based on the player's stats or always unlocked.",
"LUA_MENU_UNLOCKALL_CLASSES": "Unlock all classes",
"LUA_MENU_UNLOCKALL_CLASSES_DESC": "Whether classes should be locked based on the player's stats or always unlocked.",
"LUA_MENU_PRESTIGE": "Prestige",
"LUA_MENU_PRESTIGE_DESC": "Edit prestige level.",
"LUA_MENU_RANK": "Rank",
"LUA_MENU_RANK_DESC": "Edit rank.",
"LUA_MENU_UNSAVED_CHANGES": "You have unsaved changes: are you sure you want to exit?",
"LUA_MENU_SAVE": "Save changes",
"LUA_MENU_SAVE_DESC": "Save changes.",
"LUA_MENU_SETTINGS": "Settings",
"LUA_MENU_EDIT_STATS": "Edit Stats"
}

View File

@ -4,12 +4,14 @@
#include "console.hpp" #include "console.hpp"
#include "filesystem.hpp" #include "filesystem.hpp"
#include "localized_strings.hpp" #include "localized_strings.hpp"
#include "updater.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/hook.hpp>
#include <utils/flags.hpp> #include <utils/flags.hpp>
#include <utils/hook.hpp>
#include <utils/properties.hpp>
namespace filesystem namespace filesystem
{ {
@ -39,9 +41,9 @@ namespace filesystem
initialized = true; initialized = true;
// hardcoded paths // hardcoded paths
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
filesystem::register_path(L"."); filesystem::register_path(L".");
filesystem::register_path(L"h1-mod"); filesystem::register_path(L"h1-mod");
filesystem::register_path(L"data");
// while this clears localizations, it also calls a function to load them again // while this clears localizations, it also calls a function to load them again
localized_strings::clear(); localized_strings::clear();

View File

@ -1,6 +1,7 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "dvars.hpp" #include "dvars.hpp"
#include "updater.hpp" #include "updater.hpp"
@ -11,11 +12,12 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include <utils/nt.hpp>
#include <utils/concurrency.hpp> #include <utils/concurrency.hpp>
#include <utils/http.hpp>
#include <utils/cryptography.hpp> #include <utils/cryptography.hpp>
#include <utils/http.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/nt.hpp>
#include <utils/properties.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
#define MASTER "https://master.fed0001.xyz/h1-mod/" #define MASTER "https://master.fed0001.xyz/h1-mod/"
@ -61,6 +63,14 @@ namespace updater
std::string error{}; std::string error{};
std::string current_file{}; std::string current_file{};
std::vector<std::string> required_files{}; 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; utils::concurrency::container<update_data_t> update_data;
@ -75,6 +85,18 @@ namespace updater
return main; 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) void notify(const std::string& name)
{ {
scheduler::once([=]() scheduler::once([=]()
@ -109,10 +131,23 @@ namespace updater
bool check_file(const std::string& name, const std::string& sha) bool check_file(const std::string& name, const std::string& sha)
{ {
std::string data; std::string data;
if (get_binary_name() == name)
{
if (!utils::io::read_file(name, &data)) if (!utils::io::read_file(name, &data))
{ {
return false; 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) if (utils::cryptography::sha1::compute(data, true) != sha)
{ {
@ -122,18 +157,6 @@ namespace updater
return true; 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() std::string get_time_str()
{ {
return utils::string::va("%i", uint32_t(time(nullptr))); 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()); 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() bool is_update_cancelled()
{ {
return update_data.access<bool>([](update_data_t& data_) return update_data.access<bool>([](update_data_t& data_)
@ -161,8 +206,17 @@ namespace updater
return false; return false;
} }
if (get_binary_name() == name)
{
return utils::io::write_file(name, data); 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() 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() std::string get_mode_flag()
{ {
if (game::environment::is_mp()) if (game::environment::is_mp())
@ -199,36 +303,11 @@ namespace updater
} }
} }
// workaround
void relaunch() void relaunch()
{ {
if (!utils::io::file_exists(BINARY_NAME)) const auto mode = game::environment::is_mp() ? "-multiplayer" : "-singleplayer";
{ utils::nt::relaunch_self(mode);
utils::nt::terminate(0); utils::nt::terminate();
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);
} }
void set_has_tried_update(bool tried) void set_has_tried_update(bool tried)
@ -282,7 +361,7 @@ namespace updater
{ {
return update_data.access<bool>([](update_data_t& data_) 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() void cancel_update()
{ {
#ifdef DEBUG console::debug("[Updater] Cancelling update\n");
printf("[Updater] Cancelling update\n");
#endif
return update_data.access([](update_data_t& data_) return update_data.access([](update_data_t& data_)
{ {
@ -327,9 +404,7 @@ namespace updater
cancel_update(); cancel_update();
reset_data(); reset_data();
#ifdef DEBUG console::debug("[Updater] starting update check\n");
printf("[Updater] starting update check\n");
#endif
scheduler::once([]() scheduler::once([]()
{ {
@ -365,6 +440,7 @@ namespace updater
} }
std::vector<std::string> required_files; std::vector<std::string> required_files;
std::vector<std::string> update_files;
const auto files = j.GetArray(); const auto files = j.GetArray();
for (const auto& file : files) for (const auto& file : files)
@ -377,6 +453,8 @@ namespace updater
const auto name = file[0].GetString(); const auto name = file[0].GetString();
const auto sha = file[2].GetString(); const auto sha = file[2].GetString();
update_files.push_back(name);
if (!check_file(name, sha)) if (!check_file(name, sha))
{ {
if (get_binary_name() == name) if (get_binary_name() == name)
@ -387,19 +465,29 @@ namespace updater
}); });
} }
#ifdef DEBUG std::string name_ = name;
printf("[Updater] need file %s\n", name); if (name_.ends_with(".ff"))
#endif {
update_data.access([](update_data_t& data_)
{
data_.restart_required = true;
});
}
console::debug("[Updater] need file %s\n", name);
required_files.push_back(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.done = true;
data_.check.success = true; data_.check.success = true;
data_.required_files = required_files; data_.required_files = required_files;
data_.garbage_files = garbage_files;
}); });
notify("update_check_done"); notify("update_check_done");
@ -408,15 +496,32 @@ namespace updater
void start_update_download() void start_update_download()
{ {
#ifdef DEBUG console::debug("[Updater] starting update download\n");
printf("[Updater] starting update download\n");
#endif
if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled()) if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled())
{ {
return; 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([]() scheduler::once([]()
{ {
const auto required_files = update_data.access<std::vector<std::string>>([](update_data_t& data_) 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; data_.current_file = file;
}); });
#ifdef DEBUG console::debug("[Updater] downloading file %s\n", file.data());
printf("[Updater] downloading file %s\n", file.data());
#endif
const auto data = download_file(file); const auto data = download_file(file);

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#define CLIENT_DATA_FOLDER "cdata"
namespace updater namespace updater
{ {
void relaunch(); void relaunch();

View File

@ -6,9 +6,10 @@
#include "component/arxan.hpp" #include "component/arxan.hpp"
#include <utils/string.hpp>
#include <utils/flags.hpp> #include <utils/flags.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/string.hpp>
#include <utils/properties.hpp>
DECLSPEC_NORETURN void WINAPI exit_hook(const int code) DECLSPEC_NORETURN void WINAPI exit_hook(const int code)
{ {
@ -62,7 +63,7 @@ void apply_aslr_patch(std::string* data)
void get_aslr_patched_binary(std::string* binary, std::string* data) void get_aslr_patched_binary(std::string* binary, std::string* data)
{ {
const auto patched_binary = "h1-mod\\"s + *binary; const auto patched_binary = (utils::properties::get_appdata_path() / "bin/h1_mp64_ship.exe"s).generic_string();
try try
{ {
@ -159,6 +160,7 @@ FARPROC load_binary(const launcher::mode mode, uint64_t* base_address)
void remove_crash_file() void remove_crash_file()
{ {
utils::io::remove_file("__h1Exe"); utils::io::remove_file("__h1Exe");
utils::io::remove_file("h1-mod\\h1_mp64_ship.exe"); // remove this at some point
} }
void enable_dpi_awareness() void enable_dpi_awareness()

View File

@ -121,6 +121,18 @@ namespace utils::io
return files; return files;
} }
std::vector<std::string> list_files_recursively(const std::string& directory)
{
std::vector<std::string> files;
for (auto& file : std::filesystem::recursive_directory_iterator(directory))
{
files.push_back(file.path().generic_string());
}
return files;
}
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
{ {
std::filesystem::copy(src, target, std::filesystem::copy(src, target,

View File

@ -18,5 +18,6 @@ namespace utils::io
bool directory_is_empty(const std::string& directory); bool directory_is_empty(const std::string& directory);
bool remove_directory(const std::string& directory); bool remove_directory(const std::string& directory);
std::vector<std::string> list_files(const std::string& directory); std::vector<std::string> list_files(const std::string& directory);
std::vector<std::string> list_files_recursively(const std::string& directory);
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
} }

View File

@ -0,0 +1,24 @@
#include "io.hpp"
#include "properties.hpp"
#include <gsl/gsl>
#include <ShlObj.h>
namespace utils::properties
{
std::filesystem::path get_appdata_path()
{
PWSTR path;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path)))
{
throw std::runtime_error("Failed to read APPDATA path!");
}
auto _ = gsl::finally([&path]
{
CoTaskMemFree(path);
});
static auto appdata = std::filesystem::path(path) / "h2-mod";
return appdata;
}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace utils::properties
{
std::filesystem::path get_appdata_path();
}