Add arena file to download + fixes

This commit is contained in:
fed 2022-11-11 15:54:32 +01:00
parent 7a5798d247
commit e62fc74d98
3 changed files with 99 additions and 53 deletions

View File

@ -174,7 +174,7 @@ namespace download
const auto& result = data.value();
if (result.code != CURLE_OK)
{
menu_error(utils::string::va("Download failed: %s (%i)\n", result.code, curl_easy_strerror(result.code)));
menu_error(utils::string::va("Download failed: %s (%i)\n", curl_easy_strerror(result.code), result.code));
return;
}

View File

@ -225,8 +225,8 @@ namespace fastfiles
}
const auto& usermap_value = usermap.value();
const auto usermap_file = utils::string::va("%s.ff", usermap_value.data());
const auto usermap_load_file = utils::string::va("%s_load.ff", usermap_value.data());
const std::string usermap_file = utils::string::va("%s.ff", usermap_value.data());
const std::string usermap_load_file = utils::string::va("%s_load.ff", usermap_value.data());
if (mapname == usermap_file || mapname == usermap_load_file)
{

View File

@ -34,6 +34,20 @@ namespace party
std::string sv_motd;
int sv_maxclients;
struct usermap_file
{
std::string extension;
std::string name;
bool optional;
};
std::vector<usermap_file> usermap_files =
{
{".ff", "usermaphash", false},
{"_load.ff", "usermaploadhash", true},
{".arena", "usermaparenahash", true},
};
void perform_game_initialization()
{
command::execute("onlinegame 1", true);
@ -161,7 +175,7 @@ namespace party
cl_disconnect_hook.invoke<void>(show_main_menu);
}
std::optional<std::string> get_file_hash(const std::string& file)
std::string get_file_hash(const std::string& file)
{
if (!utils::io::file_exists(file))
{
@ -170,7 +184,12 @@ namespace party
const auto data = utils::io::read_file(file);
const auto sha = utils::cryptography::sha1::compute(data, true);
return {sha};
return sha;
}
std::string get_usermap_file_path(const std::string& mapname, const std::string& extension)
{
return utils::string::va("usermaps\\%s\\%s%s", mapname.data(), mapname.data(), extension.data());
}
void check_download_map(const utils::info_string& info, std::vector<download::file_t>& files)
@ -186,40 +205,52 @@ namespace party
throw std::runtime_error(utils::string::va("Invalid server mapname value %s\n", mapname.data()));
}
const auto check_file = [&](const std::string& key, const std::string& ext, bool optional)
const auto check_file = [&](const std::string& ext, const std::string& name, bool optional)
{
const auto filename = utils::string::va("usermaps/%s/%s%s", mapname.data(), mapname.data(), ext.data());
const auto source_hash = info.get(key);
const std::string filename = utils::string::va("usermaps/%s/%s%s", mapname.data(), mapname.data(), ext.data());
const auto source_hash = info.get(name);
if (source_hash.empty())
{
if (!optional)
{
throw std::runtime_error(utils::string::va("Server %s is empty", key.data()));
throw std::runtime_error(utils::string::va("Server %s is empty", name.data()));
}
return;
}
const auto hash = get_file_hash(filename);
if (!hash.has_value() || hash.value() != source_hash)
if (hash != source_hash)
{
files.emplace_back(filename, source_hash);
return;
}
};
check_file("usermaphash", ".ff", false);
check_file("usermaploadhash", "_load.ff", true);
for (const auto& [ext, name, opt] : usermap_files)
{
check_file(ext, name, opt);
}
}
bool check_download_mod(const utils::info_string& info, std::vector<download::file_t>& files)
{
static const auto fs_game = game::Dvar_FindVar("fs_game");
const auto client_fs_game = utils::string::to_lower(fs_game->current.string);
const auto server_fs_game = utils::string::to_lower(info.get("fs_game"));
if (server_fs_game.empty())
if (server_fs_game.empty() && client_fs_game.empty())
{
return false;
}
if (server_fs_game.empty() && !client_fs_game.empty())
{
game::Dvar_SetFromStringByNameFromSource("fs_game", "",
game::DVAR_SOURCE_INTERNAL);
return true;
}
if (!server_fs_game.starts_with("mods/") || server_fs_game.contains('.') || server_fs_game.contains("::"))
{
throw std::runtime_error(utils::string::va("Invalid server fs_game value %s\n", server_fs_game.data()));
@ -231,9 +262,6 @@ namespace party
throw std::runtime_error("Connection failed: Server mod hash is empty.");
}
static const auto fs_game = game::Dvar_FindVar("fs_game");
const auto client_fs_game = utils::string::to_lower(fs_game->current.string);
const auto mod_path = server_fs_game + "/mod.ff";
auto has_to_download = !utils::io::file_exists(mod_path);
@ -300,16 +328,24 @@ namespace party
void set_new_map(const char* mapname, const char* gametype, game::msg_t* msg)
{
char buffer[0x400] = {0};
// dont bother disconnecting just to update the usermap loadscreen
const std::string usermap_hash = game::MSG_ReadStringLine(msg,
buffer, static_cast<unsigned int>(sizeof(buffer)));
if (!game::SV_Loaded() && !fastfiles::is_stock_map(mapname))
if (game::SV_Loaded() || fastfiles::is_stock_map(mapname))
{
const auto filename = utils::string::va("usermaps\\%s\\%s.ff", mapname, mapname);
const auto hash = get_file_hash(filename);
if (!hash.has_value() || (usermap_hash.empty() || hash.value() != usermap_hash))
utils::hook::invoke<void>(0x13AAD0_b, mapname, gametype);
return;
}
for (const auto& [ext, key, opt] : usermap_files)
{
char buffer[0x100] = {0};
const std::string source_hash = game::MSG_ReadStringLine(msg,
buffer, static_cast<unsigned int>(sizeof(buffer)));
const auto path = get_usermap_file_path(mapname, ext);
const auto hash = get_file_hash(path);
console::debug("%s %s %s != %s\n", ext.data(), key.data(), hash.data(), source_hash.data());
if ((!source_hash.empty() && hash != source_hash) || (source_hash.empty() && !opt))
{
command::execute("disconnect");
scheduler::once([]
@ -354,27 +390,42 @@ namespace party
{
return net_out_of_band_print_hook.invoke<void>(sock, addr, data);
}
char buffer[0x400] = {0};
const auto is_usermap = fastfiles::usermap_exists(current_sv_mapname);
std::string hash{};
if (is_usermap)
std::string buffer{};
const auto line = [&](const std::string& data_)
{
const auto filename = utils::string::va("usermaps\\%s\\%s.ff",
current_sv_mapname.data(), current_sv_mapname.data());
const auto hash_value = get_file_hash(filename);
if (hash_value.has_value())
buffer.append(data_);
buffer.append("\n");
};
const auto* sv_gametype = game::Dvar_FindVar("g_gametype");
line("loadingnewmap");
line(current_sv_mapname);
line(sv_gametype->current.string);
const auto add_hash = [&](const std::string extension)
{
const auto filename = get_usermap_file_path(current_sv_mapname, extension);
const auto hash = get_file_hash(filename);
line(hash);
};
const auto is_usermap = fastfiles::usermap_exists(current_sv_mapname);
for (const auto& [ext, key, opt] : usermap_files)
{
if (is_usermap)
{
hash = hash_value.value();
add_hash(ext);
}
else
{
line("");
}
}
auto* sv_gametype = game::Dvar_FindVar("g_gametype");
console::debug("%i %s\n", is_usermap, buffer.data());
sprintf_s(buffer, sizeof(buffer),
"loadingnewmap\n%s\n%s\n%s", current_sv_mapname.data(), sv_gametype->current.string, hash.data());
net_out_of_band_print_hook.invoke<void>(sock, addr, buffer);
net_out_of_band_print_hook.invoke<void>(sock, addr, buffer.data());
}
}
@ -836,18 +887,16 @@ namespace party
if (!fastfiles::is_stock_map(mapname))
{
const auto hash = get_file_hash(
utils::string::va("usermaps\\%s\\%s.ff", mapname.data(), mapname.data()));
if (hash.has_value())
const auto add_hash = [&](const std::string& extension, const std::string& name)
{
info.set("usermaphash", hash.value());
}
const auto path = get_usermap_file_path(mapname, extension);
const auto hash = get_file_hash(path);
info.set(name, hash);
};
const auto load_file_hash = get_file_hash(
utils::string::va("usermaps\\%s\\%s_load.ff", mapname.data(), mapname.data()));
if (load_file_hash.has_value())
for (const auto& [ext, name, opt] : usermap_files)
{
info.set("usermaploadhash", load_file_hash.value());
add_hash(ext, name);
}
}
@ -857,10 +906,7 @@ namespace party
if (!fs_game.empty())
{
const auto hash = get_file_hash(utils::string::va("%s/mod.ff", fs_game.data()));
if (hash.has_value())
{
info.set("modHash", hash.value());
}
info.set("modHash", hash);
}
network::send(target, "infoResponse", info.build(), '\n');