Merge remote-tracking branch 'upstream/main' into favorites

This commit is contained in:
Jari van der Kaap 2023-04-15 22:07:37 +02:00
commit 764db3afea
14 changed files with 188 additions and 61 deletions

View File

@ -17,27 +17,33 @@ function __init__()
function init() function init()
{ {
level.hostname = GetDvarString( "sv_hostname"); level.hostname = GetDvarString( "sv_hostname");
if(level.hostname == "") if (level.hostname == "")
{
level.hostname = "CoDHost"; level.hostname = "CoDHost";
}
SetDvar("sv_hostname", level.hostname); SetDvar("sv_hostname", level.hostname);
SetDvar("ui_hostname", level.hostname); SetDvar("ui_hostname", level.hostname);
level.motd = GetDvarString( "scr_motd" ); level.motd = GetDvarString( "scr_motd" );
if(level.motd == "") if(level.motd == "")
{
level.motd = ""; level.motd = "";
}
SetDvar("scr_motd", level.motd); SetDvar("scr_motd", level.motd);
SetDvar("ui_motd", level.motd); SetDvar("ui_motd", level.motd);
level.allowvote = GetDvarString( "g_allowvote"); level.allowvote = GetDvarString( "g_allowvote" );
if(level.allowvote == "") if(level.allowvote == "")
{
level.allowvote = "1"; level.allowvote = "1";
}
SetDvar("g_allowvote", level.allowvote); SetDvar("g_allowvote", level.allowvote);
SetDvar("ui_allowvote", level.allowvote); SetDvar("ui_allowvote", level.allowvote);
level.allow_teamchange = "1"; level.allow_teamchange = "1";
SetDvar("ui_allow_teamchange", level.allow_teamchange); SetDvar("ui_allow_teamchange", level.allow_teamchange);
level.friendlyfire = GetGametypeSetting( "friendlyfiretype" ); level.friendlyfire = GetGametypeSetting( "friendlyfiretype" );
SetDvar("ui_friendlyfire", level.friendlyfire); SetDvar("ui_friendlyfire", level.friendlyfire);
@ -57,6 +63,8 @@ function init()
constrain_gametype(GetDvarString( "g_gametype")); constrain_gametype(GetDvarString( "g_gametype"));
constrain_map_size(level.mapsize); constrain_map_size(level.mapsize);
thread setup_callbacks();
for(;;) for(;;)
{ {
update(); update();
@ -194,3 +202,13 @@ function constrain_map_size(mapsize)
} }
} }
} }
function setup_callbacks()
{
level.onForfeit = &default_onForfeit;
}
function default_onForfeit()
{
level.gameForfeited = false;
}

2
deps/curl vendored

@ -1 +1 @@
Subproject commit dc18b40b406e9946a2198d66b6edb62575660faf Subproject commit 7ed010ce2192ae3e4d9663eaaa3a460f316b708b

2
deps/zlib vendored

@ -1 +1 @@
Subproject commit eb0e038b297f2c9877ed8b3515c6718a4b65d485 Subproject commit 5799c14c8526bf1aaa130c021982f831d155b46d

View File

@ -107,8 +107,6 @@ namespace auth
buffer.write_string(data, static_cast<size_t>(length)); buffer.write_string(data, static_cast<size_t>(length));
printf("Serialized with size: %llX\n", buffer.get_buffer().size());
return buffer.move_buffer(); return buffer.move_buffer();
} }

View File

@ -116,6 +116,9 @@ namespace client_patches
{ {
fix_amd_cpu_stuttering(); fix_amd_cpu_stuttering();
// Don't modify process priority
utils::hook::nop(0x142334C98_g, 6);
// Kill microphones for now // Kill microphones for now
utils::hook::set(0x15AAE9254_g, mixer_open_stub); utils::hook::set(0x15AAE9254_g, mixer_open_stub);

View File

@ -5,6 +5,7 @@
#include "steam/steam.hpp" #include "steam/steam.hpp"
#include "network.hpp" #include "network.hpp"
#include "workshop.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -114,6 +115,8 @@ 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_name(game::get_dvar_string("fs_game")));
info.set("fs_game", game::get_dvar_string("fs_game"));
info.set("shortversion", SHORTVERSION); info.set("shortversion", SHORTVERSION);
network::send(target, "infoResponse", info.build(), '\n'); network::send(target, "infoResponse", info.build(), '\n');

View File

@ -37,12 +37,12 @@ namespace party
} }
void connect_to_lobby(const game::netadr_t& addr, const std::string& mapname, const std::string& gamemode, void connect_to_lobby(const game::netadr_t& addr, const std::string& mapname, const std::string& gamemode,
const std::string& pub_id) const std::string& usermap_id, const std::string& mod_id)
{ {
workshop::load_usermap_mod_if_needed(pub_id); workshop::load_mod_if_needed(usermap_id, mod_id);
game::XSESSION_INFO info{}; game::XSESSION_INFO info{};
game::CL_ConnectFromLobby(0, &info, &addr, 1, 0, mapname.data(), gamemode.data(), pub_id.data()); game::CL_ConnectFromLobby(0, &info, &addr, 1, 0, mapname.data(), gamemode.data(), usermap_id.data());
} }
void launch_mode(const game::eModes mode) void launch_mode(const game::eModes mode)
@ -56,12 +56,12 @@ namespace party
} }
void connect_to_lobby_with_mode(const game::netadr_t& addr, const game::eModes mode, const std::string& mapname, void connect_to_lobby_with_mode(const game::netadr_t& addr, const game::eModes mode, const std::string& mapname,
const std::string& gametype, const std::string& pub_id, const std::string& gametype, const std::string& usermap_id, const std::string& mod_id,
const bool was_retried = false) const bool was_retried = false)
{ {
if (game::Com_SessionMode_IsMode(mode)) if (game::Com_SessionMode_IsMode(mode))
{ {
connect_to_lobby(addr, mapname, gametype, pub_id); connect_to_lobby(addr, mapname, gametype, usermap_id, mod_id);
return; return;
} }
@ -69,7 +69,7 @@ namespace party
{ {
scheduler::once([=] scheduler::once([=]
{ {
connect_to_lobby_with_mode(addr, mode, mapname, gametype, pub_id, true); connect_to_lobby_with_mode(addr, mode, mapname, gametype, usermap_id, mod_id, true);
}, scheduler::main, 5s); }, scheduler::main, 5s);
launch_mode(mode); launch_mode(mode);
@ -177,6 +177,8 @@ namespace party
return; return;
} }
const auto mod_id = info.get("fs_game");
//const auto hostname = info.get("sv_hostname"); //const auto hostname = info.get("sv_hostname");
const auto playmode = info.get("playmode"); const auto playmode = info.get("playmode");
const auto mode = static_cast<game::eModes>(std::atoi(playmode.data())); const auto mode = static_cast<game::eModes>(std::atoi(playmode.data()));
@ -184,9 +186,10 @@ namespace party
scheduler::once([=] scheduler::once([=]
{ {
const auto publisher_id = workshop::get_usermap_publisher_id(mapname); const auto usermap_id = workshop::get_usermap_publisher_id(mapname);
if (workshop::check_valid_publisher_id(mapname, publisher_id)) if (workshop::check_valid_usermap_id(mapname, usermap_id) &&
workshop::check_valid_mod_id(mod_id))
{ {
if (is_connecting_to_dedi) if (is_connecting_to_dedi)
{ {
@ -194,7 +197,7 @@ namespace party
} }
//connect_to_session(target, hostname, xuid, mode); //connect_to_session(target, hostname, xuid, mode);
connect_to_lobby_with_mode(target, mode, mapname, gametype, publisher_id); connect_to_lobby_with_mode(target, mode, mapname, gametype, usermap_id, mod_id);
} }
}, scheduler::main); }, scheduler::main);
} }

View File

@ -2,6 +2,10 @@
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include <game/game.hpp> #include <game/game.hpp>
#include <game/utils.hpp>
#include "scheduler.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
namespace patches namespace patches
@ -34,6 +38,11 @@ namespace patches
utils::hook::set<uint8_t>(game::select(0x14224DA53, 0x140531143), 3); utils::hook::set<uint8_t>(game::select(0x14224DA53, 0x140531143), 3);
utils::hook::set<uint8_t>(game::select(0x14224DBB4, 0x1405312A8), 3); utils::hook::set<uint8_t>(game::select(0x14224DBB4, 0x1405312A8), 3);
utils::hook::set<uint8_t>(game::select(0x14224DF8C, 0x1405316DC), 3); utils::hook::set<uint8_t>(game::select(0x14224DF8C, 0x1405316DC), 3);
scheduler::once([]
{
game::register_dvar_string("password", "", game::DVAR_USERINFO, "password");
}, scheduler::pipeline::main);
} }
}; };
} }

View File

@ -5,48 +5,39 @@
#include "game/game.hpp" #include "game/game.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp>
#include <utils/io.hpp>
namespace workshop namespace workshop
{ {
const std::string get_usermap_publisher_id(const std::string& mapname)
{
const auto total_usermaps = *reinterpret_cast<unsigned int*>(0x1567B3580_g);
for (unsigned int i = 0; i < total_usermaps; ++i)
{
const auto usermap_data = reinterpret_cast<game::workshop_data*>(0x1567B3588_g + (sizeof(game::workshop_data) * i));
if (usermap_data->folderName == mapname)
{
return usermap_data->publisherId;
}
}
return "";
}
bool check_valid_publisher_id(const std::string& mapname, const std::string& pub_id)
{
if (!game::DB_FileExists(mapname.data(), 0) && pub_id.empty())
{
game::Com_Error(0, "Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data());
return false;
}
return true;
}
void load_usermap_mod_if_needed(const std::string& pub_id)
{
if (!game::isModLoaded() && !pub_id.empty())
{
game::loadMod(0, "usermaps", 0);
}
}
namespace namespace
{ {
utils::hook::detour setup_server_map_hook; utils::hook::detour setup_server_map_hook;
bool has_mod(const std::string& pub_id)
{
const auto total_mods = *reinterpret_cast<unsigned int*>(0x15678D170_g);
for (unsigned int i = 0; i < total_mods; ++i)
{
const auto mod_data = reinterpret_cast<game::workshop_data*>(0x15678D178_g + (sizeof(game::workshop_data) * i));
if (mod_data->publisherId == pub_id)
{
return true;
}
}
return false;
}
void load_usermap_mod_if_needed(const std::string& publisher_id)
{
if (!game::isModLoaded() && !publisher_id.empty())
{
game::loadMod(0, "usermaps", true);
}
}
void setup_server_map_stub(int localClientNum, const char* mapname, const char* gametype) void setup_server_map_stub(int localClientNum, const char* mapname, const char* gametype)
{ {
const auto publisher_id = get_usermap_publisher_id(mapname); const auto publisher_id = get_usermap_publisher_id(mapname);
@ -72,6 +63,102 @@ namespace workshop
} }
} }
std::string get_mod_name(const std::string& mod_id)
{
if (mod_id == "usermaps" || !game::is_server())
{
return mod_id;
}
const utils::nt::library host{};
const auto base_path = host.get_folder().generic_string();
const auto path = utils::string::va("%s/mods/%s/zone/workshop.json", base_path.data(), mod_id.data());
const auto json_str = utils::io::read_file(path);
if (json_str.empty())
{
printf("[ Workshop ] workshop.json has not been found in mod folder: %s\n", mod_id.data());
return mod_id;
}
rapidjson::Document doc;
const rapidjson::ParseResult parse_result = doc.Parse(json_str);
if (parse_result.IsError() || !doc.IsObject())
{
printf("[ Workshop ] Unable to parse workshop.json\n");
return mod_id;
}
if (doc.HasMember("Title"))
{
std::string title = doc["Title"].GetString();
if (title.size() > 31)
{
title.resize(31);
}
return title;
}
printf("[ Workshop ] workshop.json has no \"Title\" member.\n");
return mod_id;
}
std::string get_usermap_publisher_id(const std::string& mapname)
{
const auto total_usermaps = *reinterpret_cast<unsigned int*>(0x1567B3580_g);
for (unsigned int i = 0; i < total_usermaps; ++i)
{
const auto usermap_data = reinterpret_cast<game::workshop_data*>(0x1567B3588_g + (sizeof(game::workshop_data) * i));
if (usermap_data->folderName == mapname)
{
return usermap_data->publisherId;
}
}
return {};
}
bool check_valid_usermap_id(const std::string& mapname, const std::string& pub_id)
{
if (!game::DB_FileExists(mapname.data(), 0) && pub_id.empty())
{
game::UI_OpenErrorPopupWithMessage(0, 0x100,
utils::string::va("Can't find usermap: %s!\nMake sure you're subscribed to the workshop item.", mapname.data()));
return false;
}
return true;
}
bool check_valid_mod_id(const std::string& mod)
{
if (mod.empty() || mod == "usermaps")
{
return true;
}
if (!has_mod(mod))
{
game::UI_OpenErrorPopupWithMessage(0, 0x100,
utils::string::va("Can't find mod with publisher id: %s!\nMake sure you're subscribed to the workshop item.", mod.data()));
return false;
}
return true;
}
void load_mod_if_needed(const std::string& usermap, const std::string& mod)
{
if (!usermap.empty() || mod != "usermaps")
{
game::loadMod(0, mod.data(), true);
}
}
class component final : public client_component class component final : public client_component
{ {
public: public:

View File

@ -2,7 +2,9 @@
namespace workshop namespace workshop
{ {
const std::string get_usermap_publisher_id(const std::string& mapname); std::string get_usermap_publisher_id(const std::string& mapname);
bool check_valid_publisher_id(const std::string& mapname, const std::string& pub_id); std::string get_mod_name(const std::string& mod_id);
void load_usermap_mod_if_needed(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);
void load_mod_if_needed(const std::string& usermap, const std::string& mod);
} }

View File

@ -104,7 +104,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<void(int, const char*, int)> loadMod{0x1420D6930}; WEAK symbol<void(int, const char*, bool)> loadMod{0x1420D6930};
// Dvar // Dvar
WEAK symbol<bool(const dvar_t* dvar)> Dvar_IsSessionModeBaseDvar{0x1422C23A0, 0x140576890}; WEAK symbol<bool(const dvar_t* dvar)> Dvar_IsSessionModeBaseDvar{0x1422C23A0, 0x140576890};
@ -145,6 +145,7 @@ namespace game
}; };
// UI // UI
WEAK symbol<void(int localClientNumber, int errorcode, const char* errorMessage)> UI_OpenErrorPopupWithMessage{0x14228DEE0};
WEAK symbol<void(bool frontend)> UI_CoD_Init{0x141F29010, 0x1404A0A50}; WEAK symbol<void(bool frontend)> UI_CoD_Init{0x141F29010, 0x1404A0A50};
WEAK symbol<void()> UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50}; WEAK symbol<void()> UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50};
WEAK symbol<void()> UI_CoD_Shutdown{0x141F32E10, 0x0}; WEAK symbol<void()> UI_CoD_Shutdown{0x141F32E10, 0x0};

View File

@ -58,12 +58,14 @@ namespace steam
const auto mode = game::eModes(std::atoi(playmode.data())); const auto mode = game::eModes(std::atoi(playmode.data()));
const auto* tags = ::utils::string::va( const auto* tags = ::utils::string::va(
R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\modName\\playerCount\%d\bots\%d\)", R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\playerCount\%d\bots\%d\modName\%s\)",
info.get("gametype").data(), info.get("gametype").data(),
info.get("dedicated") == "1" ? "true" : "false", info.get("dedicated") == "1" ? "true" : "false",
info.get("hc") == "1" ? "true" : "false", info.get("hc") == "1" ? "true" : "false",
mode == game::MODE_ZOMBIES ? "true" : "false", mode == game::MODE_ZOMBIES ? "true" : "false",
server.m_nPlayers, atoi(info.get("bots").data())); server.m_nPlayers,
atoi(info.get("bots").data()),
info.get("modname").data());
::utils::string::copy(server.m_szGameTags, tags); ::utils::string::copy(server.m_szGameTags, tags);
server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16); server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16);

View File

@ -194,18 +194,19 @@ namespace utils::io
std::vector<std::filesystem::path> list_files(const std::filesystem::path& directory, const bool recursive) std::vector<std::filesystem::path> list_files(const std::filesystem::path& directory, const bool recursive)
{ {
std::error_code code{};
std::vector<std::filesystem::path> files; std::vector<std::filesystem::path> files;
if (recursive) if (recursive)
{ {
for (auto& file : std::filesystem::recursive_directory_iterator(directory)) for (auto& file : std::filesystem::recursive_directory_iterator(directory, code))
{ {
files.push_back(file.path()); files.push_back(file.path());
} }
} }
else else
{ {
for (auto& file : std::filesystem::directory_iterator(directory)) for (auto& file : std::filesystem::directory_iterator(directory, code))
{ {
files.push_back(file.path()); files.push_back(file.path());
} }