Merge branch 'main' of https://github.com/mjkzy/boiii into scripts
This commit is contained in:
commit
32f8dbb9f1
@ -42,7 +42,7 @@ DataSources.LobbyServer = {
|
|||||||
SetModelValue(serverModel, "modName", serverInfo.modName)
|
SetModelValue(serverModel, "modName", serverInfo.modName)
|
||||||
SetModelValue(serverModel, "mapName", serverInfo.map)
|
SetModelValue(serverModel, "mapName", serverInfo.map)
|
||||||
SetModelValue(serverModel, "desc", serverInfo.desc)
|
SetModelValue(serverModel, "desc", serverInfo.desc)
|
||||||
-- Changed the client count to be the actual player count
|
-- Change the client count to be the actual player count
|
||||||
local clientCount = serverInfo.playerCount - serverInfo.botCount
|
local clientCount = serverInfo.playerCount - serverInfo.botCount
|
||||||
SetModelValue(serverModel, "clientCount", clientCount)
|
SetModelValue(serverModel, "clientCount", clientCount)
|
||||||
SetModelValue(serverModel, "maxClients", serverInfo.maxPlayers)
|
SetModelValue(serverModel, "maxClients", serverInfo.maxPlayers)
|
||||||
@ -54,7 +54,7 @@ DataSources.LobbyServer = {
|
|||||||
SetModelValue(serverModel, "ranked", serverInfo.ranked)
|
SetModelValue(serverModel, "ranked", serverInfo.ranked)
|
||||||
SetModelValue(serverModel, "hardcore", serverInfo.hardcore)
|
SetModelValue(serverModel, "hardcore", serverInfo.hardcore)
|
||||||
SetModelValue(serverModel, "zombies", serverInfo.zombies)
|
SetModelValue(serverModel, "zombies", serverInfo.zombies)
|
||||||
-- Added the bot count
|
-- Add the bot count
|
||||||
SetModelValue(serverModel, "botCount", serverInfo.botCount)
|
SetModelValue(serverModel, "botCount", serverInfo.botCount)
|
||||||
return serverModel
|
return serverModel
|
||||||
else
|
else
|
||||||
|
2
deps/curl
vendored
2
deps/curl
vendored
@ -1 +1 @@
|
|||||||
Subproject commit d8df0d6db7441b6e14920a7e16a10e32bdc9c7ae
|
Subproject commit 8e21b1a05f3c0ee098dbcb6c3d84cb61f102a122
|
@ -85,6 +85,12 @@ namespace chat
|
|||||||
a.cmp(dword_ptr(rax, 0x16AE0), 0x0); // game's code
|
a.cmp(dword_ptr(rax, 0x16AE0), 0x0); // game's code
|
||||||
a.jmp(0x14029905B_g);
|
a.jmp(0x14029905B_g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cl_handle_chat(char* dest, size_t dest_size, const char* src)
|
||||||
|
{
|
||||||
|
game::I_strcpy(dest, dest_size, src);
|
||||||
|
printf("%s\n", dest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* get_client_name(const uint64_t xuid)
|
const char* get_client_name(const uint64_t xuid)
|
||||||
@ -96,7 +102,7 @@ namespace chat
|
|||||||
|
|
||||||
if (xuid < 19 && !game::is_server())
|
if (xuid < 19 && !game::is_server())
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256]{};
|
||||||
game::CL_GetClientName(0, static_cast<int>(xuid - 1), buffer, sizeof(buffer), true);
|
game::CL_GetClientName(0, static_cast<int>(xuid - 1), buffer, sizeof(buffer), true);
|
||||||
|
|
||||||
return utils::string::va("%s\n", buffer);
|
return utils::string::va("%s\n", buffer);
|
||||||
@ -167,6 +173,9 @@ namespace chat
|
|||||||
{
|
{
|
||||||
// Ignore some check that suppresses the chat
|
// Ignore some check that suppresses the chat
|
||||||
utils::hook::nop(0x141DEA9BD_g, 2);
|
utils::hook::nop(0x141DEA9BD_g, 2);
|
||||||
|
|
||||||
|
// Add chat history to the in-game console
|
||||||
|
utils::hook::call(0x141DEAA0F_g, cl_handle_chat); // I_strcpy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -116,8 +116,9 @@ namespace getinfo
|
|||||||
info.set("sv_running", std::to_string(game::is_server_running()));
|
info.set("sv_running", std::to_string(game::is_server_running()));
|
||||||
info.set("dedicated", game::is_server() ? "1" : "0");
|
info.set("dedicated", game::is_server() ? "1" : "0");
|
||||||
info.set("hc", std::to_string(game::Com_GametypeSettings_GetUInt("hardcoremode", false)));
|
info.set("hc", std::to_string(game::Com_GametypeSettings_GetUInt("hardcoremode", false)));
|
||||||
info.set("modName", workshop::get_mod_resized_name(game::get_dvar_string("fs_game")));
|
info.set("modName", workshop::get_mod_resized_name());
|
||||||
info.set("modId", workshop::get_mod_publisher_id(game::get_dvar_string("fs_game")));
|
info.set("modId", workshop::get_mod_publisher_id());
|
||||||
|
info.set("rounds_played", std::to_string(*game::level_rounds_played));
|
||||||
info.set("shortversion", SHORTVERSION);
|
info.set("shortversion", SHORTVERSION);
|
||||||
|
|
||||||
network::send(target, "infoResponse", info.build(), '\n');
|
network::send(target, "infoResponse", info.build(), '\n');
|
||||||
|
@ -79,7 +79,6 @@ namespace script
|
|||||||
{
|
{
|
||||||
if (data.size() >= sizeof(GSC_MAGIC) && !std::memcmp(data.data(), &GSC_MAGIC, sizeof(GSC_MAGIC)))
|
if (data.size() >= sizeof(GSC_MAGIC) && !std::memcmp(data.data(), &GSC_MAGIC, sizeof(GSC_MAGIC)))
|
||||||
{
|
{
|
||||||
auto base_name = script_file.substr(0, script_file.size() - 4);
|
|
||||||
print_loading_script(script_file);
|
print_loading_script(script_file);
|
||||||
load_script(script_file, data);
|
load_script(script_file, data);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace server_list
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
utils::hook::detour lua_serverinfo_to_table_hook;
|
utils::hook::detour lua_server_info_to_table_hook;
|
||||||
|
|
||||||
struct state
|
struct state
|
||||||
{
|
{
|
||||||
@ -80,14 +80,14 @@ namespace server_list
|
|||||||
callback(true, result);
|
callback(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_serverinfo_to_table_stub(game::hks::lua_State* state, game::ServerInfo serverInfo, int index)
|
void lua_server_info_to_table_stub(game::hks::lua_State* state, game::ServerInfo server_info, int index)
|
||||||
{
|
{
|
||||||
lua_serverinfo_to_table_hook.invoke(state, serverInfo, index);
|
lua_server_info_to_table_hook.invoke(state, server_info, index);
|
||||||
|
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
auto botCount = atoi(game::Info_ValueForKey(serverInfo.tags, "bots"));
|
const auto bot_count = atoi(game::Info_ValueForKey(server_info.tags, "bots"));
|
||||||
game::Lua_SetTableInt("botCount", botCount, state);
|
game::Lua_SetTableInt("botCount", bot_count, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,13 +98,14 @@ namespace server_list
|
|||||||
|
|
||||||
void write_favorite_servers()
|
void write_favorite_servers()
|
||||||
{
|
{
|
||||||
favorite_servers.access([&](std::unordered_set<game::netadr_t>& servers)
|
favorite_servers.access([](const std::unordered_set<game::netadr_t>& servers)
|
||||||
{
|
{
|
||||||
std::string servers_buffer = "";
|
std::string servers_buffer{};
|
||||||
for (auto itr : servers)
|
for (const auto& itr : servers)
|
||||||
{
|
{
|
||||||
servers_buffer.append(utils::string::va("%i.%i.%i.%i:%u\n", itr.ipv4.a, itr.ipv4.b, itr.ipv4.c, itr.ipv4.d, itr.port));
|
servers_buffer.append(utils::string::va("%i.%i.%i.%i:%hu\n", itr.ipv4.a, itr.ipv4.b, itr.ipv4.c, itr.ipv4.d, itr.port));
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::io::write_file(get_favorite_servers_file_path(), servers_buffer);
|
utils::io::write_file(get_favorite_servers_file_path(), servers_buffer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -120,11 +121,12 @@ namespace server_list
|
|||||||
favorite_servers.access([&path](std::unordered_set<game::netadr_t>& servers)
|
favorite_servers.access([&path](std::unordered_set<game::netadr_t>& servers)
|
||||||
{
|
{
|
||||||
servers.clear();
|
servers.clear();
|
||||||
std::string filedata;
|
|
||||||
if (utils::io::read_file(path, &filedata))
|
std::string data;
|
||||||
|
if (utils::io::read_file(path, &data))
|
||||||
{
|
{
|
||||||
auto srv = utils::string::split(filedata, '\n');
|
const auto srv = utils::string::split(data, '\n');
|
||||||
for (auto server_address : srv)
|
for (const auto& server_address : srv)
|
||||||
{
|
{
|
||||||
auto server = network::address_from_string(server_address);
|
auto server = network::address_from_string(server_address);
|
||||||
servers.insert(server);
|
servers.insert(server);
|
||||||
@ -222,7 +224,7 @@ namespace server_list
|
|||||||
});
|
});
|
||||||
}, scheduler::async, 200ms);
|
}, scheduler::async, 200ms);
|
||||||
|
|
||||||
lua_serverinfo_to_table_hook.create(0x141F1FD10_g, lua_serverinfo_to_table_stub);
|
lua_server_info_to_table_hook.create(0x141F1FD10_g, lua_server_info_to_table_stub);
|
||||||
|
|
||||||
scheduler::once([]
|
scheduler::once([]
|
||||||
{
|
{
|
||||||
|
@ -170,32 +170,34 @@ namespace workshop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mod_resized_name(const std::string& dir_name)
|
std::string get_mod_resized_name()
|
||||||
{
|
{
|
||||||
if (dir_name == "usermaps" || dir_name.empty())
|
const std::string loaded_mod_id = game::getPublisherIdFromLoadedMod();
|
||||||
|
|
||||||
|
if (loaded_mod_id == "usermaps" || loaded_mod_id.empty())
|
||||||
{
|
{
|
||||||
return dir_name;
|
return loaded_mod_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result = dir_name;
|
std::string mod_name = loaded_mod_id;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < *game::modsCount; ++i)
|
for (unsigned int i = 0; i < *game::modsCount; ++i)
|
||||||
{
|
{
|
||||||
const auto& mod_data = game::modsPool[i];
|
const auto& mod_data = game::modsPool[i];
|
||||||
|
|
||||||
if (utils::string::ends_with(mod_data.contentPathToZoneFiles, dir_name))
|
if (mod_data.publisherId == loaded_mod_id)
|
||||||
{
|
{
|
||||||
result = mod_data.title;
|
mod_name = mod_data.title;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.size() > 31)
|
if (mod_name.size() > 31)
|
||||||
{
|
{
|
||||||
result.resize(31);
|
mod_name.resize(31);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return mod_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_usermap_publisher_id(const std::string& zone_name)
|
std::string get_usermap_publisher_id(const std::string& zone_name)
|
||||||
@ -218,29 +220,22 @@ namespace workshop
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mod_publisher_id(const std::string& dir_name)
|
std::string get_mod_publisher_id()
|
||||||
{
|
{
|
||||||
if (dir_name == "usermaps" || dir_name.empty())
|
const std::string loaded_mod_id = game::getPublisherIdFromLoadedMod();
|
||||||
|
|
||||||
|
if (loaded_mod_id == "usermaps" || loaded_mod_id.empty())
|
||||||
{
|
{
|
||||||
return dir_name;
|
return loaded_mod_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < *game::modsCount; ++i)
|
if (!utils::string::is_numeric(loaded_mod_id))
|
||||||
{
|
{
|
||||||
const auto& mod_data = game::modsPool[i];
|
printf("[ Workshop ] WARNING: The publisherId: %s, is not numerical you might have set your mod folder incorrectly!\n",
|
||||||
if (utils::string::ends_with(mod_data.contentPathToZoneFiles, dir_name))
|
loaded_mod_id.data());
|
||||||
{
|
|
||||||
if (!utils::string::is_numeric(mod_data.publisherId))
|
|
||||||
{
|
|
||||||
printf("[ Workshop ] WARNING: The publisherId is not numerical you might have set your mod folder incorrectly!\n%s\n",
|
|
||||||
mod_data.absolutePathZoneFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mod_data.publisherId;
|
return loaded_mod_id;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id)
|
bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id)
|
||||||
@ -274,6 +269,11 @@ namespace workshop
|
|||||||
|
|
||||||
void setup_same_mod_as_host(const std::string& usermap, const std::string& mod)
|
void setup_same_mod_as_host(const std::string& usermap, const std::string& mod)
|
||||||
{
|
{
|
||||||
|
if (game::getPublisherIdFromLoadedMod() == mod)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!usermap.empty() || mod != "usermaps")
|
if (!usermap.empty() || mod != "usermaps")
|
||||||
{
|
{
|
||||||
game::loadMod(0, mod.data(), true);
|
game::loadMod(0, mod.data(), true);
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
namespace workshop
|
namespace workshop
|
||||||
{
|
{
|
||||||
std::string get_usermap_publisher_id(const std::string& folder_name);
|
std::string get_usermap_publisher_id(const std::string& folder_name);
|
||||||
std::string get_mod_publisher_id(const std::string& folder_name);
|
std::string get_mod_publisher_id();
|
||||||
std::string get_mod_resized_name(const std::string& folder_name);
|
std::string get_mod_resized_name();
|
||||||
bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id);
|
bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id);
|
||||||
bool check_valid_mod_id(const std::string& pub_id);
|
bool check_valid_mod_id(const std::string& pub_id);
|
||||||
void setup_same_mod_as_host(const std::string& usermap, const std::string& mod);
|
void setup_same_mod_as_host(const std::string& usermap, const std::string& mod);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PROTOCOL 6
|
#define PROTOCOL 7
|
||||||
#define SUB_PROTOCOL 1
|
#define SUB_PROTOCOL 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -114,6 +114,7 @@ namespace game
|
|||||||
WEAK symbol<const char*(const char* name)> CopyString{0x1422AC220, 0x14056BD70};
|
WEAK symbol<const char*(const char* name)> CopyString{0x1422AC220, 0x14056BD70};
|
||||||
|
|
||||||
WEAK symbol<bool()> isModLoaded{0x1420D5020};
|
WEAK symbol<bool()> isModLoaded{0x1420D5020};
|
||||||
|
WEAK symbol<const char*()> getPublisherIdFromLoadedMod{0x1420D7680, 0x1404E3230};
|
||||||
WEAK symbol<void(int localClientNum, const char* mod, bool)> loadMod{0x1420D6930};
|
WEAK symbol<void(int localClientNum, const char* mod, bool)> loadMod{0x1420D6930};
|
||||||
WEAK symbol<void()> reloadUserContent{0x1420D66C0, 0x1404E25C0};
|
WEAK symbol<void()> reloadUserContent{0x1420D66C0, 0x1404E25C0};
|
||||||
|
|
||||||
@ -214,6 +215,9 @@ namespace game
|
|||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
WEAK symbol<const char*(char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
WEAK symbol<const char*(char* str)> I_CleanStr{0x1422E9050, 0x140580E80};
|
||||||
|
WEAK symbol<void(char* dest, size_t destsize, const char* src)> I_strcpy{
|
||||||
|
0x1422E9410, 0x1405811E0
|
||||||
|
};
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
WEAK symbol<cmd_function_s> cmd_functions{0x15689DF58, 0x14946F860};
|
WEAK symbol<cmd_function_s> cmd_functions{0x15689DF58, 0x14946F860};
|
||||||
@ -222,6 +226,7 @@ namespace game
|
|||||||
WEAK symbol<gentity_s> g_entities{0x0, 0x1471031B0};
|
WEAK symbol<gentity_s> g_entities{0x0, 0x1471031B0};
|
||||||
|
|
||||||
WEAK symbol<int> level_time{0x0, 0x1474FDC94};
|
WEAK symbol<int> level_time{0x0, 0x1474FDC94};
|
||||||
|
WEAK symbol<int> level_rounds_played{0x14A55BDEC, 0x1475097BC};
|
||||||
|
|
||||||
WEAK symbol<SOCKET> ip_socket{0x157E75818, 0x14A640988};
|
WEAK symbol<SOCKET> ip_socket{0x157E75818, 0x14A640988};
|
||||||
|
|
||||||
|
@ -292,6 +292,11 @@ namespace
|
|||||||
|
|
||||||
const auto is_server = utils::flags::has_flag("dedicated") || (!has_client && has_server);
|
const auto is_server = utils::flags::has_flag("dedicated") || (!has_client && has_server);
|
||||||
|
|
||||||
|
if (!has_client && !has_server)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Can't find a valid BlackOps3.exe or BlackOps3_UnrankedDedicatedServer.exe. Make sure you put boiii.exe in your Black Ops 3 installation folder.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_server)
|
if (!is_server)
|
||||||
{
|
{
|
||||||
trigger_high_performance_gpu_switch();
|
trigger_high_performance_gpu_switch();
|
||||||
|
@ -224,9 +224,7 @@ namespace utils::cryptography
|
|||||||
{
|
{
|
||||||
this->free();
|
this->free();
|
||||||
|
|
||||||
if (ecc_import(cs(key.data()), ul(key.size()),
|
if (ecc_import(cs(key.data()), ul(key.size()), &this->key_storage_) != CRYPT_OK)
|
||||||
&this->key_storage_) != CRYPT_OK
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||||
}
|
}
|
||||||
@ -242,7 +240,7 @@ namespace utils::cryptography
|
|||||||
return {cs(buffer), length};
|
return {cs(buffer), length};
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ecc::key::get_openssl() const
|
std::string ecc::key::get_openssl() const
|
||||||
@ -255,7 +253,17 @@ namespace utils::cryptography
|
|||||||
return {cs(buffer), length};
|
return {cs(buffer), length};
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ecc::key::set_openssl(const std::string& key)
|
||||||
|
{
|
||||||
|
this->free();
|
||||||
|
|
||||||
|
if (ecc_import_openssl(cs(key.data()), ul(key.size()), &this->key_storage_) != CRYPT_OK)
|
||||||
|
{
|
||||||
|
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ecc::key::free()
|
void ecc::key::free()
|
||||||
@ -305,12 +313,14 @@ namespace utils::cryptography
|
|||||||
|
|
||||||
std::string ecc::sign_message(const key& key, const std::string& message)
|
std::string ecc::sign_message(const key& key, const std::string& message)
|
||||||
{
|
{
|
||||||
if (!key.is_valid()) return "";
|
if (!key.is_valid()) return {};
|
||||||
|
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
unsigned long length = sizeof(buffer);
|
unsigned long length = sizeof(buffer);
|
||||||
|
|
||||||
ecc_sign_hash(cs(message.data()), ul(message.size()), buffer, &length, prng_.get_state(), prng_.get_id(),
|
const auto hash = sha512::compute(message);
|
||||||
|
|
||||||
|
ecc_sign_hash(cs(hash.data()), ul(hash.size()), buffer, &length, prng_.get_state(), prng_.get_id(),
|
||||||
&key.get());
|
&key.get());
|
||||||
|
|
||||||
return std::string(cs(buffer), length);
|
return std::string(cs(buffer), length);
|
||||||
@ -320,11 +330,13 @@ namespace utils::cryptography
|
|||||||
{
|
{
|
||||||
if (!key.is_valid()) return false;
|
if (!key.is_valid()) return false;
|
||||||
|
|
||||||
|
const auto hash = sha512::compute(message);
|
||||||
|
|
||||||
auto result = 0;
|
auto result = 0;
|
||||||
return (ecc_verify_hash(cs(signature.data()),
|
return (ecc_verify_hash(cs(signature.data()),
|
||||||
ul(signature.size()),
|
ul(signature.size()),
|
||||||
cs(message.data()),
|
cs(hash.data()),
|
||||||
ul(message.size()), &result,
|
ul(hash.size()), &result,
|
||||||
&key.get()) == CRYPT_OK && result != 0);
|
&key.get()) == CRYPT_OK && result != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +408,6 @@ namespace utils::cryptography
|
|||||||
rsa_free(&new_key);
|
rsa_free(&new_key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
std::string out_data{};
|
std::string out_data{};
|
||||||
out_data.resize(std::max(ul(data.size() * 3), ul(0x100)));
|
out_data.resize(std::max(ul(data.size() * 3), ul(0x100)));
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ namespace utils::cryptography
|
|||||||
std::string serialize(int type = PK_PRIVATE) const;
|
std::string serialize(int type = PK_PRIVATE) const;
|
||||||
|
|
||||||
std::string get_openssl() const;
|
std::string get_openssl() const;
|
||||||
|
void set_openssl(const std::string& key);
|
||||||
|
|
||||||
void free();
|
void free();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user