Skip to content

Commit

Permalink
fastdl init
Browse files Browse the repository at this point in the history
  • Loading branch information
Joelrau committed Aug 4, 2024
1 parent 131196c commit 31761e8
Show file tree
Hide file tree
Showing 11 changed files with 623 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/client/component/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ namespace command
client_command_mp_hook.create(0x140B105D0, &client_command_mp);
client_command_sp_hook.create(0x140483130, &client_command_sp);

parse_commandline_hook.create(0x140F2F67B, parse_commandline);
parse_commandline_hook.create(0x140C039F0, parse_commandline); // SL_Init

add_commands();
}
Expand Down
257 changes: 257 additions & 0 deletions src/client/component/download.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"

#include "download.hpp"
#include "console/console.hpp"
#include "scheduler.hpp"
#include "party.hpp"

#include "game/ui_scripting/execution.hpp"

#include "utils/hash.hpp"

#include <utils/concurrency.hpp>
#include <utils/http.hpp>
#include <utils/io.hpp>
#include <utils/cryptography.hpp>

namespace download
{
namespace
{
struct globals_t
{
bool abort{};
bool active{};
};

std::atomic_bool kill_downloads = false;
utils::concurrency::container<globals_t> globals;

bool download_aborted()
{
if (kill_downloads)
{
return true;
}

return globals.access<bool>([](globals_t& globals_)
{
return globals_.abort;
});
}

void mark_unactive()
{
globals.access([](globals_t& globals_)
{
globals_.active = false;
});
}

void mark_active()
{
globals.access([](globals_t& globals_)
{
globals_.active = true;
});
}

bool download_active()
{
return globals.access<bool>([](globals_t& globals_)
{
return globals_.active;
});
}

auto last_update = std::chrono::high_resolution_clock::now();
int progress_callback(size_t total, size_t progress)
{
const auto now = std::chrono::high_resolution_clock::now();
if (now - last_update > 20ms)
{
last_update = std::chrono::high_resolution_clock::now();
auto fraction = 0.f;
if (total > 0)
{
fraction = static_cast<float>(static_cast<double>(progress) /
static_cast<double>(total));
}

scheduler::once([=]
{
ui_scripting::notify("mod_download_progress",
{
{"fraction", fraction},
});
}, scheduler::pipeline::lui);
}

//console::debug("Download progress: %lli/%lli\n", progress, total);
if (download_aborted())
{
return -1;
}

return 0;
}

void menu_error(const std::string& error)
{
scheduler::once([=]
{
game::shared::menu_error(error);
}, scheduler::pipeline::lui);
}
}

void start_download(const game::netadr_s& target, const utils::info_string& info, const std::vector<file_t>& files)
{
if (download_active())
{
scheduler::schedule([=]
{
if (!download_active())
{
start_download(target, info, files);
return scheduler::cond_end;
}

return scheduler::cond_continue;
}, scheduler::pipeline::main);

return;
}

globals.access([&](globals_t& globals_)
{
globals_ = {};
});

const auto base = info.get("sv_wwwBaseUrl");
if (base.empty())
{
menu_error("Download failed: Server doesn't have 'sv_wwwBaseUrl' dvar set.");
return;
}

scheduler::once([]
{
ui_scripting::notify("mod_download_start", {});
}, scheduler::pipeline::lui);

scheduler::once([=]
{
{
const auto _0 = gsl::finally(&mark_unactive);
mark_active();

if (download_aborted())
{
return;
}

for (const auto& file : files)
{
scheduler::once([=]
{
const ui_scripting::table data_table{};
data_table.set("name", file.name.data());

ui_scripting::notify("mod_download_set_file",
{
{"request", data_table}
});
}, scheduler::pipeline::lui);

const auto url = utils::string::va("%s/%s", base.data(), file.name.data());
console::debug("Downloading %s from %s: %s\n", file.name.data(), base.data(), url);
auto data = utils::http::get_data(url, {}, {}, &progress_callback);
if (!data.has_value())
{
menu_error(utils::string::va("Download failed: An unknown error occurred when getting data from '%s', please try again.", url));
return;
}

if (download_aborted())
{
return;
}

auto& result = data.value();
if (result.code != CURLE_OK)
{
if (result.code == CURLE_COULDNT_CONNECT)
{
menu_error(utils::string::va("Download failed: Couldn't connect to server '%s' (%i)\n",
url, result.code));
return;
}

menu_error(utils::string::va("Download failed: %s (%i)\n",
curl_easy_strerror(result.code), result.code));
return;
}

if (result.response_code >= 400)
{
menu_error(utils::string::va("Download failed: Server returned bad response code (%i)\n",
result.response_code));
return;
}

const auto hash = utils::hash::get_buffer_hash(result.buffer, file.name);
if (hash != file.hash)
{
menu_error(utils::string::va("Download failed: File hash doesn't match the server's (%s: %s != %s)\n",
file.name.data(), hash.data(), file.hash.data()));
return;
}

utils::io::write_file(file.name, result.buffer, false);
}
}

scheduler::once([]
{
ui_scripting::notify("mod_download_done", {});
}, scheduler::pipeline::lui);

scheduler::once([target]
{
party::connect(target);
}, scheduler::pipeline::main);
}, scheduler::pipeline::async);
}

void stop_download()
{
if (!download_active())
{
return;
}

globals.access([&](globals_t& globals_)
{
globals_.abort = true;
});

scheduler::once([]
{
ui_scripting::notify("mod_download_done", {});
game::shared::menu_error("Download failed: Aborted");
}, scheduler::pipeline::lui);
}

class component final : public component_interface
{
public:
void pre_destroy() override
{
kill_downloads = true;
}
};
}

REGISTER_COMPONENT(download::component)
17 changes: 17 additions & 0 deletions src/client/component/download.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "game/game.hpp"

#include <utils/info_string.hpp>

namespace download
{
struct file_t
{
std::string name;
std::string hash;
};

void start_download(const game::netadr_s& target, const utils::info_string& info, const std::vector<file_t>& files);
void stop_download();
}
10 changes: 6 additions & 4 deletions src/client/component/fastfiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ namespace fastfiles

// mod is loaded on map start

if (fastfiles::exists("mod"))
{
data.push_back({ "mod", game::DB_ZONE_GAME | game::DB_ZONE_CUSTOM, 0 });
}
//if (fastfiles::exists("mod"))
//{
// data.push_back({ "mod", game::DB_ZONE_GAME | game::DB_ZONE_CUSTOM, 0 });
//}

game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
}
Expand Down Expand Up @@ -222,6 +222,8 @@ namespace fastfiles
add_zone("iw7mod_ui_mp", game::DB_ZONE_UI | game::DB_ZONE_CUSTOM, 0);
}

add_zone("mod", game::DB_ZONE_GLOBAL_TIER1 | game::DB_ZONE_CUSTOM, 1);

game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
}
}
Expand Down
Loading

0 comments on commit 31761e8

Please sign in to comment.