fix(FontMgr): also keep in mind game language when generating font texture (#2892)

This commit is contained in:
Andreas Maerten 2024-07-23 08:47:38 +02:00 committed by GitHub
parent 286a54045f
commit 9885b68014
15 changed files with 333 additions and 274 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Ignore all differences in line endings
* -crlf

View File

@ -1,26 +1,21 @@
#pragma once #pragma once
#include "gta/enums.hpp"
namespace big namespace big
{ {
struct LanguageType const std::map<eGameLanguage, const std::string_view> languages = {
{ {eGameLanguage::ENGLISH, "English"},
uint32_t id; {eGameLanguage::FRENCH, "French"},
const char name[32]; {eGameLanguage::GERMAN, "German"},
}; {eGameLanguage::ITALIAN, "Italian"},
{eGameLanguage::SPANISH, "Spanish (Spain)"},
const LanguageType languages[] = { {eGameLanguage::BRAZILIAN_PORTUGUESE, "Portuguese (Brazil)"},
{0, "English"}, {eGameLanguage::POLISH, "Polish"},
{1, "French"}, {eGameLanguage::RUSSIAN, "Russian"},
{2, "German"}, {eGameLanguage::KOREAN, "Korean"},
{3, "Italian"}, {eGameLanguage::TRADITIONAL_CHINESE, "Chinese (Traditional)"},
{4, "Spanish (Spain)"}, {eGameLanguage::JAPANESE, "Japanese"},
{5, "Portuguese (Brazil)"}, {eGameLanguage::MEXICAN_SPANISH, "Spanish (Mexico)"},
{6, "Polish"}, {eGameLanguage::SIMPLIFIED_CHINESE, "Chinese (Simpified)"},
{7, "Russian"},
{8, "Korean"},
{9, "Chinese (Traditional)"},
{10, "Japanese"},
{11, "Spanish (Mexico)"},
{12, "Chinese (Simpified)"},
}; };
} }

View File

@ -2,6 +2,7 @@
#include "backend/reactions/interloper_reaction.hpp" #include "backend/reactions/interloper_reaction.hpp"
#include "backend/reactions/reaction.hpp" #include "backend/reactions/reaction.hpp"
#include "core/data/hud_colors.hpp" #include "core/data/hud_colors.hpp"
#include "core/data/language_codes.hpp"
#include "core/data/ptfx_effects.hpp" #include "core/data/ptfx_effects.hpp"
#include "enums.hpp" #include "enums.hpp"
#include "file_manager.hpp" #include "file_manager.hpp"
@ -723,7 +724,7 @@ namespace big
bool spoof_session_region_type = false; bool spoof_session_region_type = false;
int session_region_type = 0; int session_region_type = 0;
bool spoof_session_language = false; bool spoof_session_language = false;
int session_language = 0; eGameLanguage session_language = eGameLanguage::ENGLISH;
bool spoof_session_player_count = false; bool spoof_session_player_count = false;
int session_player_count = 25; int session_player_count = 25;
int spoof_session_bad_sport_status = 0; int spoof_session_bad_sport_status = 0;
@ -1053,7 +1054,7 @@ namespace big
int region_filter = 0; int region_filter = 0;
bool language_filter_enabled = false; bool language_filter_enabled = false;
int language_filter = 0; eGameLanguage language_filter = eGameLanguage::ENGLISH;
bool pool_filter_enabled = false; bool pool_filter_enabled = false;
int pool_filter = 0; int pool_filter = 0;

View File

@ -3,6 +3,24 @@
constexpr auto MAX_PLAYERS = 32; constexpr auto MAX_PLAYERS = 32;
enum class eGameLanguage : int
{
ENGLISH,
FRENCH,
GERMAN,
ITALIAN,
SPANISH,
BRAZILIAN_PORTUGUESE,
POLISH,
RUSSIAN,
KOREAN,
TRADITIONAL_CHINESE,
JAPANESE,
MEXICAN_SPANISH,
SIMPLIFIED_CHINESE
};
NLOHMANN_JSON_SERIALIZE_ENUM(eGameLanguage, {{eGameLanguage::ENGLISH, "english"}, {eGameLanguage::FRENCH, "french"}, {eGameLanguage::GERMAN, "german"}, {eGameLanguage::ITALIAN, "italian"}, {eGameLanguage::SPANISH, "spanish"}, {eGameLanguage::BRAZILIAN_PORTUGUESE, "brazilian_portuguese"}, {eGameLanguage::POLISH, "polish"}, {eGameLanguage::RUSSIAN, "russian"}, {eGameLanguage::KOREAN, "korean"}, {eGameLanguage::TRADITIONAL_CHINESE, "traditional_chinese"}, {eGameLanguage::JAPANESE, "japanese"}, {eGameLanguage::MEXICAN_SPANISH, "mexican_spanish"}, {eGameLanguage::SIMPLIFIED_CHINESE, "simplified_chinese"}})
enum class ControllerInputs : uint32_t enum class ControllerInputs : uint32_t
{ {
INPUT_NEXT_CAMERA, INPUT_NEXT_CAMERA,
@ -1976,18 +1994,18 @@ enum class eTaskTypeIndex
enum class eTaskFlags enum class eTaskFlags
{ {
ParachuteWhenCoordThresholdIsReached = 1 << 3, ParachuteWhenCoordThresholdIsReached = 1 << 3,
CamShakeOnFall = 1 << 4, CamShakeOnFall = 1 << 4,
PlayRagdollAnim = 1 << 5, PlayRagdollAnim = 1 << 5,
PlayDiveAnim = 1 << 7, PlayDiveAnim = 1 << 7,
NoFallAnimation = 1 << 10, NoFallAnimation = 1 << 10,
NoSlowFall = 1 << 11, NoSlowFall = 1 << 11,
Unk12 = 1 << 12, Unk12 = 1 << 12,
SuperJump = 1 << 15, SuperJump = 1 << 15,
LandOnJump = 1 << 16, LandOnJump = 1 << 16,
BeastJump = 1 << 17, BeastJump = 1 << 17,
BeastJumpWithSuper = SuperJump | BeastJump, BeastJumpWithSuper = SuperJump | BeastJump,
GracefulLanding = NoFallAnimation | NoSlowFall | Unk12 | LandOnJump, GracefulLanding = NoFallAnimation | NoSlowFall | Unk12 | LandOnJump,
RagdollOnFall = BeastJump | PlayRagdollAnim RagdollOnFall = BeastJump | PlayRagdollAnim
}; };
enum class eDoorId enum class eDoorId

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "function_types.hpp" #include "function_types.hpp"
#include "gta/enums.hpp"
#include <memory/handle.hpp> #include <memory/handle.hpp>
@ -284,7 +285,7 @@ namespace big
functions::handle_chat_message m_handle_chat_message; functions::handle_chat_message m_handle_chat_message;
int* m_language; eGameLanguage* m_language;
functions::update_language m_update_language; functions::update_language m_update_language;
PVOID m_model_spawn_bypass; PVOID m_model_spawn_bypass;

View File

@ -12,6 +12,7 @@
#include "util/session.hpp" #include "util/session.hpp"
#include "util/system.hpp" #include "util/system.hpp"
#include "util/teleport.hpp" #include "util/teleport.hpp"
#include <script/globals/GPBD_FM.hpp> #include <script/globals/GPBD_FM.hpp>
#include <script/globals/GPBD_FM_3.hpp> #include <script/globals/GPBD_FM_3.hpp>
@ -202,7 +203,6 @@ namespace lua::network
if (auto player = big::g_player_service->get_by_id(player_idx)) if (auto player = big::g_player_service->get_by_id(player_idx))
{ {
big::chat::send_message(msg, player); big::chat::send_message(msg, player);
} }
} }
@ -306,7 +306,7 @@ namespace lua::network
if (big::g_player_service->get_by_id(pid)) if (big::g_player_service->get_by_id(pid))
{ {
auto& boss_goon = big::scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[pid].BossGoon; auto& boss_goon = big::scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[pid].BossGoon;
return big::languages[boss_goon.Language].name; return big::languages.at((eGameLanguage)boss_goon.Language).data();
} }
return "Unknown"; return "Unknown";
} }
@ -343,19 +343,19 @@ namespace lua::network
ns["set_all_player_coords"] = set_all_player_coords; ns["set_all_player_coords"] = set_all_player_coords;
ns["get_selected_player"] = get_selected_player; ns["get_selected_player"] = get_selected_player;
ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id; ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id;
ns["flag_player_as_modder"] = sol::overload(flag_player_as_modder, flag_player_as_modder_custom_reason); ns["flag_player_as_modder"] = sol::overload(flag_player_as_modder, flag_player_as_modder_custom_reason);
ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder; ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder;
ns["is_player_friend"] = is_player_friend; ns["is_player_friend"] = is_player_friend;
ns["get_flagged_modder_reason"] = get_flagged_modder_reason; ns["get_flagged_modder_reason"] = get_flagged_modder_reason;
ns["force_script_host"] = force_script_host; ns["force_script_host"] = force_script_host;
ns["send_chat_message"] = send_chat_message; ns["send_chat_message"] = send_chat_message;
ns["send_chat_message_to_player"] = send_chat_message_to_player; ns["send_chat_message_to_player"] = send_chat_message_to_player;
ns["get_player_rank"] = get_player_rank; ns["get_player_rank"] = get_player_rank;
ns["get_player_rp"] = get_player_rp; ns["get_player_rp"] = get_player_rp;
ns["get_player_money"] = get_player_money; ns["get_player_money"] = get_player_money;
ns["get_player_wallet"] = get_player_wallet; ns["get_player_wallet"] = get_player_wallet;
ns["get_player_bank"] = get_player_bank; ns["get_player_bank"] = get_player_bank;
ns["get_player_language_id"] = get_player_language_id; ns["get_player_language_id"] = get_player_language_id;
ns["get_player_language_name"] = get_player_language_name; ns["get_player_language_name"] = get_player_language_name;
} }
} }

View File

@ -1210,7 +1210,7 @@ namespace big
"83 3D ? ? ? ? ? 44 8B C3", "83 3D ? ? ? ? ? 44 8B C3",
[](memory::handle ptr) [](memory::handle ptr)
{ {
g_pointers->m_gta.m_language = ptr.add(2).rip().add(1).as<int*>(); g_pointers->m_gta.m_language = ptr.add(2).rip().add(1).as<eGameLanguage*>();
g_pointers->m_gta.m_update_language = ptr.add(0x38).rip().as<functions::update_language>(); g_pointers->m_gta.m_update_language = ptr.add(0x38).rip().as<functions::update_language>();
} }
}, },

View File

@ -1,6 +1,7 @@
#include "font_mgr.hpp" #include "font_mgr.hpp"
#include "fonts/fonts.hpp" #include "fonts/fonts.hpp"
#include "pointers.hpp"
#include "renderer.hpp" #include "renderer.hpp"
#include "thread_pool.hpp" #include "thread_pool.hpp"
@ -29,57 +30,51 @@ namespace big
m_update_lock.unlock(); m_update_lock.unlock();
} }
void font_mgr::update_required_alphabet_type(eAlphabetType type)
{
m_require_extra = type;
g_thread_pool->push([this] {
rebuild();
});
}
void font_mgr::rebuild() void font_mgr::rebuild()
{ {
m_update_lock.lock(); m_update_lock.lock();
g_renderer.pre_reset(); g_renderer.pre_reset();
const auto extra_font_file = get_available_font_file_for_alphabet_type();
if (m_require_extra != eAlphabetType::LATIN && !extra_font_file.exists())
{
LOG(WARNING) << "Could not find an appropriate font for the current language!";
}
const auto extra_glyph_range = get_imgui_alphabet_type();
auto& io = ImGui::GetIO(); auto& io = ImGui::GetIO();
io.Fonts->Clear(); io.Fonts->Clear();
// default font size const auto required_alphabet_types = get_required_alphabet_types();
{
ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, "Fnt20px");
io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia),
sizeof(font_storopia),
20.f,
&fnt_cfg,
io.Fonts->GetGlyphRangesDefault());
if (m_require_extra != eAlphabetType::LATIN && extra_font_file.exists())
{
fnt_cfg.MergeMode = true;
io.Fonts->AddFontFromFileTTF(extra_font_file.get_path().string().c_str(), 20.f, &fnt_cfg, extra_glyph_range);
}
io.Fonts->Build();
}
// any other font sizes we need to support
for (auto [size, font_ptr] : m_extra_font_sizes) for (auto [size, font_ptr] : m_extra_font_sizes)
{ {
ImFontConfig fnt_cfg{}; ImFontConfig fnt_cfg{};
fnt_cfg.FontDataOwnedByAtlas = false; fnt_cfg.FontDataOwnedByAtlas = false;
strcpy(fnt_cfg.Name, std::format("Fnt{}px", (int)size).c_str()); strcpy(fnt_cfg.Name, std::format("Fnt{}px", (int)size).c_str());
*font_ptr = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia), const auto tmp_ptr = io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font_storopia),
sizeof(font_storopia), sizeof(font_storopia),
size, size,
&fnt_cfg, &fnt_cfg,
io.Fonts->GetGlyphRangesDefault()); io.Fonts->GetGlyphRangesDefault());
if (m_require_extra != eAlphabetType::LATIN && extra_font_file.exists()) if (font_ptr)
{ {
fnt_cfg.MergeMode = true; *font_ptr = tmp_ptr;
io.Fonts->AddFontFromFileTTF(extra_font_file.get_path().string().c_str(), size, &fnt_cfg, extra_glyph_range); }
for (const auto required_type : required_alphabet_types)
{
const auto font_file = get_available_font_file_for_alphabet_type(required_type);
const auto glyph_range = get_imgui_alphabet_type(required_type);
if (required_type != eAlphabetType::LATIN && font_file.exists())
{
fnt_cfg.MergeMode = true;
io.Fonts->AddFontFromFileTTF(font_file.get_path().string().c_str(), size, &fnt_cfg, glyph_range);
}
} }
io.Fonts->Build(); io.Fonts->Build();
} }
@ -97,20 +92,11 @@ namespace big
m_update_lock.unlock(); m_update_lock.unlock();
} }
void font_mgr::update_required_alphabet_type(eAlphabetType type) file font_mgr::get_available_font_file_for_alphabet_type(const eAlphabetType type) const
{
m_require_extra = type;
g_thread_pool->push([this] {
rebuild();
});
}
file font_mgr::get_available_font_file_for_alphabet_type()
{ {
static const auto fonts_folder = std::filesystem::path(std::getenv("SYSTEMROOT")) / "Fonts"; static const auto fonts_folder = std::filesystem::path(std::getenv("SYSTEMROOT")) / "Fonts";
const auto& fonts = m_fonts.find(m_require_extra); const auto& fonts = m_fonts.find(type);
if (fonts == m_fonts.end()) if (fonts == m_fonts.end())
return {}; return {};
for (const auto& font : fonts->second) for (const auto& font : fonts->second)
@ -124,6 +110,45 @@ namespace big
return {}; return {};
} }
const std::unordered_set<eAlphabetType> font_mgr::get_required_alphabet_types() const
{
auto required_alphabet_types = std::unordered_set<eAlphabetType>({eAlphabetType::LATIN});
required_alphabet_types.insert(get_game_language_alphabet_type());
required_alphabet_types.insert(m_require_extra);
return required_alphabet_types;
}
eAlphabetType font_mgr::get_game_language_alphabet_type()
{
switch (*g_pointers->m_gta.m_language)
{
case eGameLanguage::RUSSIAN: return eAlphabetType::CYRILLIC;
case eGameLanguage::JAPANESE: return eAlphabetType::JAPANESE;
case eGameLanguage::KOREAN: return eAlphabetType::KOREAN;
case eGameLanguage::SIMPLIFIED_CHINESE:
case eGameLanguage::TRADITIONAL_CHINESE: return eAlphabetType::CHINESE;
}
return eAlphabetType::LATIN;
}
const ImWchar* font_mgr::get_imgui_alphabet_type(const eAlphabetType type)
{
auto& io = ImGui::GetIO();
switch (type)
{
case eAlphabetType::CHINESE: return GetGlyphRangesChineseSimplifiedOfficial();
case eAlphabetType::CYRILLIC: return io.Fonts->GetGlyphRangesCyrillic();
case eAlphabetType::JAPANESE: return io.Fonts->GetGlyphRangesJapanese();
case eAlphabetType::KOREAN: return io.Fonts->GetGlyphRangesKorean();
case eAlphabetType::TURKISH: return GetGlyphRangesTurkish();
default:
case eAlphabetType::LATIN: return io.Fonts->GetGlyphRangesDefault();
}
}
const ImWchar* font_mgr::GetGlyphRangesChineseSimplifiedOfficial() const ImWchar* font_mgr::GetGlyphRangesChineseSimplifiedOfficial()
{ {
// Store all official characters for Simplified Chinese. // Store all official characters for Simplified Chinese.
@ -190,20 +215,4 @@ namespace big
}; };
return &icons_ranges_Turkish[0]; return &icons_ranges_Turkish[0];
} }
const ImWchar* font_mgr::get_imgui_alphabet_type()
{
auto& io = ImGui::GetIO();
switch (m_require_extra)
{
case eAlphabetType::CHINESE: return GetGlyphRangesChineseSimplifiedOfficial();
case eAlphabetType::CYRILLIC: return io.Fonts->GetGlyphRangesCyrillic();
case eAlphabetType::JAPANESE: return io.Fonts->GetGlyphRangesJapanese();
case eAlphabetType::KOREAN: return io.Fonts->GetGlyphRangesKorean();
case eAlphabetType::TURKISH: return GetGlyphRangesTurkish();
default:
case eAlphabetType::LATIN: return io.Fonts->GetGlyphRangesDefault();
}
}
} }

View File

@ -15,7 +15,8 @@ namespace big
std::mutex m_update_lock; std::mutex m_update_lock;
public: public:
font_mgr(std::vector<std::pair<float, ImFont**>> extra_font_sizes = {{28.f, &g.window.font_title}, font_mgr(std::vector<std::pair<float, ImFont**>> extra_font_sizes = {{20.f, nullptr},
{28.f, &g.window.font_title},
{24.f, &g.window.font_sub_title}, {24.f, &g.window.font_sub_title},
{18.f, &g.window.font_small}}); {18.f, &g.window.font_small}});
virtual ~font_mgr() = default; virtual ~font_mgr() = default;
@ -33,9 +34,14 @@ namespace big
private: private:
void rebuild(); void rebuild();
file get_available_font_file_for_alphabet_type(); file get_available_font_file_for_alphabet_type(const eAlphabetType type) const;
const ImWchar* GetGlyphRangesChineseSimplifiedOfficial(); const std::unordered_set<eAlphabetType> get_required_alphabet_types() const;
const ImWchar* GetGlyphRangesTurkish();
const ImWchar* get_imgui_alphabet_type(); static eAlphabetType get_game_language_alphabet_type();
static const ImWchar* get_imgui_alphabet_type(const eAlphabetType type);
static const ImWchar* GetGlyphRangesChineseSimplifiedOfficial();
static const ImWchar* GetGlyphRangesTurkish();
}; };
} }

View File

@ -1,9 +1,9 @@
#include "matchmaking_service.hpp" #include "matchmaking_service.hpp"
#include "fiber_pool.hpp"
#include "hooking/hooking.hpp" #include "hooking/hooking.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "script.hpp" #include "script.hpp"
#include "fiber_pool.hpp"
#include <network/Network.hpp> #include <network/Network.hpp>
@ -25,7 +25,7 @@ namespace big
attributes->m_param_values[4] = g.spoofing.session_region_type; attributes->m_param_values[4] = g.spoofing.session_region_type;
if (g.spoofing.spoof_session_language) if (g.spoofing.spoof_session_language)
attributes->m_param_values[3] = g.spoofing.session_language; attributes->m_param_values[3] = (uint32_t)g.spoofing.session_language;
if (g.spoofing.spoof_session_player_count && g.spoofing.increase_player_limit) if (g.spoofing.spoof_session_player_count && g.spoofing.increase_player_limit)
attributes->m_param_values[2] = std::min(29, g.spoofing.session_player_count); attributes->m_param_values[2] = std::min(29, g.spoofing.session_player_count);
@ -68,7 +68,7 @@ namespace big
rage::rlTaskStatus state{}; rage::rlTaskStatus state{};
static rage::rlSessionInfo result_sessions[MAX_SESSIONS_TO_FIND]; static rage::rlSessionInfo result_sessions[MAX_SESSIONS_TO_FIND];
m_active = true; m_active = true;
m_num_valid_sessions = 0; m_num_valid_sessions = 0;
if (g_hooking->get_original<hooks::start_matchmaking_find_sessions>()(0, 1, &component, MAX_SESSIONS_TO_FIND, result_sessions, &m_num_sessions_found, &state)) if (g_hooking->get_original<hooks::start_matchmaking_find_sessions>()(0, 1, &component, MAX_SESSIONS_TO_FIND, result_sessions, &m_num_sessions_found, &state))
@ -101,7 +101,7 @@ namespace big
m_found_sessions[i].is_valid = false; m_found_sessions[i].is_valid = false;
if (g.session_browser.language_filter_enabled if (g.session_browser.language_filter_enabled
&& m_found_sessions[i].attributes.language != g.session_browser.language_filter) && (eGameLanguage)m_found_sessions[i].attributes.language != g.session_browser.language_filter)
m_found_sessions[i].is_valid = false; m_found_sessions[i].is_valid = false;
if (g.session_browser.player_count_filter_enabled if (g.session_browser.player_count_filter_enabled
@ -190,10 +190,10 @@ namespace big
} }
MatchmakingId primary_id = *out_id; // create a copy if the original memory gets deallocated MatchmakingId primary_id = *out_id; // create a copy if the original memory gets deallocated
std::uint32_t id_hash = rage::joaat(primary_id.m_data1); std::uint32_t id_hash = rage::joaat(primary_id.m_data1);
// m_data1 is generated from m_data2 and m_data3 // m_data1 is generated from m_data2 and m_data3
m_multiplexed_sessions.emplace(id_hash, std::vector<MatchmakingId>{ }); m_multiplexed_sessions.emplace(id_hash, std::vector<MatchmakingId>{});
// create multiplex advertisements // create multiplex advertisements
for (int i = 0; i < (g.spoofing.multiplex_count - 1); i++) for (int i = 0; i < (g.spoofing.multiplex_count - 1); i++)
@ -264,7 +264,6 @@ namespace big
LOG(WARNING) << __FUNCTION__ ": update_session_advertisement failed for multiplex task " << i; LOG(WARNING) << __FUNCTION__ ": update_session_advertisement failed for multiplex task " << i;
return; return;
} }
}); });
i++; i++;
} }

View File

@ -295,21 +295,21 @@ namespace big
switch (game_lang) switch (game_lang)
{ {
case 1: preferred_lang = "fr_FR"; break; case eGameLanguage::FRENCH: preferred_lang = "fr_FR"; break;
case 2: preferred_lang = "de_DE"; break; case eGameLanguage::GERMAN: preferred_lang = "de_DE"; break;
case 3: preferred_lang = "it_IT"; break; case eGameLanguage::ITALIAN: preferred_lang = "it_IT"; break;
case 4: case eGameLanguage::SPANISH:
case 11: preferred_lang = "es_ES"; break; case eGameLanguage::MEXICAN_SPANISH: preferred_lang = "es_ES"; break;
case 5: preferred_lang = "pt_BR"; break; case eGameLanguage::BRAZILIAN_PORTUGUESE: preferred_lang = "pt_BR"; break;
case 6: preferred_lang = "pl_PL"; break; case eGameLanguage::POLISH: preferred_lang = "pl_PL"; break;
case 7: preferred_lang = "ru_RU"; break; case eGameLanguage::RUSSIAN: preferred_lang = "ru_RU"; break;
case 8: preferred_lang = "ko_KR"; break; case eGameLanguage::KOREAN: preferred_lang = "ko_KR"; break;
case 9: preferred_lang = "zh_TW"; break; case eGameLanguage::TRADITIONAL_CHINESE: preferred_lang = "zh_TW"; break;
case 10: preferred_lang = "ja_JP"; break; case eGameLanguage::JAPANESE: preferred_lang = "ja_JP"; break;
case 12: preferred_lang = "zh_CN"; break; case eGameLanguage::SIMPLIFIED_CHINESE: preferred_lang = "zh_CN"; break;
} }
if (game_lang == 12 || game_lang == 9) if (game_lang == eGameLanguage::SIMPLIFIED_CHINESE || game_lang == eGameLanguage::TRADITIONAL_CHINESE)
{ {
// Tweaks to make it easier for people playing in the China region // Tweaks to make it easier for people playing in the China region
g.session_browser.filter_multiplexed_sessions = true; g.session_browser.filter_multiplexed_sessions = true;

View File

@ -19,7 +19,8 @@ namespace big
static char name_buf[32]; static char name_buf[32];
static char search[64]; static char search[64];
static char session_info[0x100]{}; static char session_info[0x100]{};
ImGui::Text(std::format("{}: {}", "VIEW_SESSION_TOTAL_SESSIONS_FOUND"_T.data(), g_matchmaking_service->get_num_found_sessions()).c_str()); ImGui::Text(std::format("{}: {}", "VIEW_SESSION_TOTAL_SESSIONS_FOUND"_T.data(), g_matchmaking_service->get_num_found_sessions())
.c_str());
ImGui::SetNextItemWidth(300.f); ImGui::SetNextItemWidth(300.f);
@ -41,11 +42,11 @@ namespace big
session_str = std::format("{:X}", session.info.m_session_token); session_str = std::format("{:X}", session.info.m_session_token);
auto host_rid = session.info.m_net_player_data.m_gamer_handle.m_rockstar_id; auto host_rid = session.info.m_net_player_data.m_gamer_handle.m_rockstar_id;
auto player = g_player_database_service->get_player_by_rockstar_id(host_rid); auto player = g_player_database_service->get_player_by_rockstar_id(host_rid);
if ((g.session_browser.exclude_modder_sessions && player && player->block_join) || if ((g.session_browser.exclude_modder_sessions && player && player->block_join)
(g.session_browser.filter_multiplexed_sessions && session.attributes.multiplex_count > 1)) || (g.session_browser.filter_multiplexed_sessions && session.attributes.multiplex_count > 1))
continue; continue;
if (components::selectable(session_str, i == selected_session_idx)) if (components::selectable(session_str, i == selected_session_idx))
{ {
@ -55,11 +56,17 @@ namespace big
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
auto tool_tip = std::format("{}: {}\n{}: {}\n{}: {}\n{}: {}\n{}: {:X}", "SESSION_BROWSER_NUM_PLAYERS"_T, session.attributes.player_count, auto tool_tip = std::format("{}: {}\n{}: {}\n{}: {}\n{}: {}\n{}: {:X}",
"REGION"_T, regions[session.attributes.region].name, "SESSION_BROWSER_NUM_PLAYERS"_T,
"LANGUAGE"_T, languages[session.attributes.language].name, session.attributes.player_count,
"SESSION_BROWSER_HOST_RID"_T, session.info.m_net_player_data.m_gamer_handle.m_rockstar_id, // TODO: this is not accurate "REGION"_T,
"SESSION_BROWSER_DISCRIMINATOR"_T, session.attributes.discriminator); regions[session.attributes.region].name,
"LANGUAGE"_T,
languages.at((eGameLanguage)session.attributes.language),
"SESSION_BROWSER_HOST_RID"_T,
session.info.m_net_player_data.m_gamer_handle.m_rockstar_id, // TODO: this is not accurate
"SESSION_BROWSER_DISCRIMINATOR"_T,
session.attributes.discriminator);
ImGui::SetTooltip(tool_tip.c_str()); ImGui::SetTooltip(tool_tip.c_str());
} }
} }
@ -80,9 +87,11 @@ namespace big
auto& session = g_matchmaking_service->get_found_sessions()[selected_session_idx]; auto& session = g_matchmaking_service->get_found_sessions()[selected_session_idx];
ImGui::Text(std::format("{}: {}", "SESSION_BROWSER_NUM_PLAYERS"_T, session.attributes.player_count).c_str()); ImGui::Text(std::format("{}: {}", "SESSION_BROWSER_NUM_PLAYERS"_T, session.attributes.player_count).c_str());
ImGui::Text(std::format("{}: 0x{:X}", "SESSION_BROWSER_DISCRIMINATOR"_T, session.attributes.discriminator).c_str()); ImGui::Text(
std::format("{}: 0x{:X}", "SESSION_BROWSER_DISCRIMINATOR"_T, session.attributes.discriminator).c_str());
ImGui::Text(std::format("{}: {}", "REGION"_T, regions[session.attributes.region].name).c_str()); ImGui::Text(std::format("{}: {}", "REGION"_T, regions[session.attributes.region].name).c_str());
ImGui::Text(std::format("{}: {}", "LANGUAGE"_T, languages[session.attributes.language].name).c_str()); ImGui::Text(
std::format("{}: {}", "LANGUAGE"_T, languages.at((eGameLanguage)session.attributes.language)).c_str());
auto& data = session.info.m_net_player_data; auto& data = session.info.m_net_player_data;
ImGui::Text(std::format("{}: {}", "SESSION_BROWSER_HOST_RID"_T, data.m_gamer_handle.m_rockstar_id).c_str()); ImGui::Text(std::format("{}: {}", "SESSION_BROWSER_HOST_RID"_T, data.m_gamer_handle.m_rockstar_id).c_str());
@ -143,13 +152,13 @@ namespace big
{ {
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::BeginCombo("###language_select", languages[g.session_browser.language_filter].name)) if (ImGui::BeginCombo("###language_select", languages.at(g.session_browser.language_filter).data()))
{ {
for (const auto& language : languages) for (const auto& [id, language] : languages)
{ {
if (ImGui::Selectable(language.name, g.session_browser.language_filter == language.id)) if (ImGui::Selectable(language.data(), g.session_browser.language_filter == id))
{ {
g.session_browser.language_filter = language.id; g.session_browser.language_filter = id;
}; };
} }
ImGui::EndCombo(); ImGui::EndCombo();
@ -168,7 +177,8 @@ namespace big
if (g.session_browser.pool_filter_enabled) if (g.session_browser.pool_filter_enabled)
{ {
ImGui::SameLine(); ImGui::SameLine();
static const std::string pool_filter_options = std::string("NORMAL"_T.data()) + '\0' + std::string("BAD_SPORT"_T.data()); static const std::string pool_filter_options =
std::string("NORMAL"_T.data()) + '\0' + std::string("BAD_SPORT"_T.data());
ImGui::Combo("###pooltype", &g.session_browser.pool_filter, pool_filter_options.c_str()); ImGui::Combo("###pooltype", &g.session_browser.pool_filter, pool_filter_options.c_str());
} }
@ -186,7 +196,8 @@ namespace big
if (ImGui::TreeNode("SORTING"_T.data())) if (ImGui::TreeNode("SORTING"_T.data()))
{ {
static const std::string sort_by_options = std::string("OFF"_T.data()) + '\0' + std::string("PLAYER_COUNT"_T.data()); static const std::string sort_by_options = std::string("OFF"_T.data()) + '\0' + std::string("PLAYER_COUNT"_T.data());
static const std::string sort_direction_options = std::string("ASCENDING"_T.data()) + '\0' + std::string("DESCENDING"_T.data()); static const std::string sort_direction_options =
std::string("ASCENDING"_T.data()) + '\0' + std::string("DESCENDING"_T.data());
ImGui::Combo("SORT_BY"_T.data(), &g.session_browser.sort_method, sort_by_options.c_str()); ImGui::Combo("SORT_BY"_T.data(), &g.session_browser.sort_method, sort_by_options.c_str());
if (g.session_browser.sort_method != 0) if (g.session_browser.sort_method != 0)
ImGui::Combo("DIRECTION"_T.data(), &g.session_browser.sort_direction, sort_direction_options.c_str()); ImGui::Combo("DIRECTION"_T.data(), &g.session_browser.sort_direction, sort_direction_options.c_str());

View File

@ -130,13 +130,13 @@ namespace big
{ {
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::BeginCombo("###language_select", languages[g.spoofing.session_language].name)) if (ImGui::BeginCombo("###language_select", languages.at(g.spoofing.session_language).data()))
{ {
for (const auto& language : languages) for (const auto& [id, language] : languages)
{ {
if (ImGui::Selectable(language.name, g.spoofing.session_language == language.id)) if (ImGui::Selectable(language.data(), g.spoofing.session_language == id))
{ {
g.spoofing.session_language = language.id; g.spoofing.session_language = id;
}; };
} }
ImGui::EndCombo(); ImGui::EndCombo();

View File

@ -2,10 +2,10 @@
#include "core/data/language_codes.hpp" #include "core/data/language_codes.hpp"
#include "core/scr_globals.hpp" #include "core/scr_globals.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "services/player_database/player_database_service.hpp"
#include "views/view.hpp"
#include "services/gta_data/gta_data_service.hpp" #include "services/gta_data/gta_data_service.hpp"
#include "services/player_database/player_database_service.hpp"
#include "util/session.hpp" #include "util/session.hpp"
#include "views/view.hpp"
#include <network/netConnection.hpp> #include <network/netConnection.hpp>
#include <script/globals/GPBD_FM.hpp> #include <script/globals/GPBD_FM.hpp>
@ -19,9 +19,9 @@ namespace big
{ {
switch (type) switch (type)
{ {
case 1: return "VIEW_PLAYER_INFO_NAT_TYPE_OPEN"_T.data(); case 1: return "VIEW_PLAYER_INFO_NAT_TYPE_OPEN"_T.data();
case 2: return "VIEW_PLAYER_INFO_NAT_TYPE_MODERATE"_T.data(); case 2: return "VIEW_PLAYER_INFO_NAT_TYPE_MODERATE"_T.data();
case 3: return "VIEW_PLAYER_INFO_NAT_TYPE_STRICT"_T.data(); case 3: return "VIEW_PLAYER_INFO_NAT_TYPE_STRICT"_T.data();
} }
return "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data(); return "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data();
@ -31,9 +31,9 @@ namespace big
{ {
switch (type) switch (type)
{ {
case 1: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_DIRECT"_T.data(); case 1: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_DIRECT"_T.data();
case 2: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_RELAY"_T.data(); case 2: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_RELAY"_T.data();
case 3: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_PEER_RELAY"_T.data(); case 3: return "VIEW_PLAYER_INFO_CONNECTION_TYPE_PEER_RELAY"_T.data();
} }
return "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data(); return "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data();
@ -60,118 +60,135 @@ namespace big
} }
components::options_modal( components::options_modal(
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(), "VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(),
[ped_health, ped_maxhealth] { [ped_health, ped_maxhealth] {
ImGui::BeginGroup(); ImGui::BeginGroup();
auto id = g_player_service->get_selected()->id(); auto id = g_player_service->get_selected()->id();
if (id != -1) if (id != -1)
{ {
auto& stats = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].PlayerStats; auto& stats = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].PlayerStats;
auto& boss_goon = scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[id].BossGoon; auto& boss_goon = scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[id].BossGoon;
const auto money = reinterpret_cast<uint64_t&>(stats.Money); const auto money = reinterpret_cast<uint64_t&>(stats.Money);
const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance); const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance);
if (boss_goon.Language >= 0 && boss_goon.Language < 13) if (boss_goon.Language >= 0 && boss_goon.Language < 13)
ImGui::Text("PLAYER_INFO_LANGUAGE"_T.data(), languages[boss_goon.Language].name); ImGui::Text("PLAYER_INFO_LANGUAGE"_T.data(), languages.at((eGameLanguage)boss_goon.Language).data());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_CEO_NAME"_T, boss_goon.GangName.Data).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_CEO_NAME"_T, boss_goon.GangName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MC_NAME"_T, boss_goon.ClubhouseName.Data).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MC_NAME"_T, boss_goon.ClubhouseName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_WALLET"_T, wallet).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_WALLET"_T, wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_BANK"_T, money - wallet).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_BANK"_T, money - wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_TOTAL_MONEY"_T, money).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_TOTAL_MONEY"_T, money).c_str());
ImGui::Text(std::format("{}: {} ({} {})", "PLAYER_INFO_RANK"_T, stats.Rank, "PLAYER_INFO_RANK_RP"_T, stats.RP).c_str()); ImGui::Text(
ImGui::Text(std::format("{}: {} ({} {})", "VIEW_PLAYER_INFO_HEALTH"_T, ped_health, "VIEW_PLAYER_INFO_MAXHEALTH"_T, ped_maxhealth).c_str()); std::format("{}: {} ({} {})", "PLAYER_INFO_RANK"_T, stats.Rank, "PLAYER_INFO_RANK_RP"_T, stats.RP)
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KD"_T, stats.KdRatio).c_str()); .c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KILLS"_T, stats.KillsOnPlayers).c_str()); ImGui::Text(std::format("{}: {} ({} {})", "VIEW_PLAYER_INFO_HEALTH"_T, ped_health, "VIEW_PLAYER_INFO_MAXHEALTH"_T, ped_maxhealth)
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_DEATHS"_T, stats.DeathsByPlayers).c_str()); .c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_PROSTITUTES"_T, stats.ProstitutesFrequented).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KD"_T, stats.KdRatio).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_LAP_DANCES"_T, stats.LapDancesBought).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KILLS"_T, stats.KillsOnPlayers).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MISSIONS_CREATED"_T, stats.MissionsCreated).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_DEATHS"_T, stats.DeathsByPlayers).c_str());
auto meltdown_completed = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].MeltdownComplete ? "YES"_T : "NO"_T; ImGui::Text(std::format("{}: {}", "PLAYER_INFO_PROSTITUTES"_T, stats.ProstitutesFrequented).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_METLDOWN_COMPLETE"_T, meltdown_completed).c_str()); ImGui::Text(std::format("{}: {}", "PLAYER_INFO_LAP_DANCES"_T, stats.LapDancesBought).c_str());
} ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MISSIONS_CREATED"_T, stats.MissionsCreated).c_str());
auto meltdown_completed = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].MeltdownComplete ? "YES"_T : "NO"_T;
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_METLDOWN_COMPLETE"_T, meltdown_completed).c_str());
}
ImGui::EndGroup(); ImGui::EndGroup();
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NAT_TYPE"_T, get_nat_type_str(g_player_service->get_selected()->get_net_data()->m_nat_type)).c_str()); ImGui::Text(std::format("{}: {}",
"VIEW_PLAYER_INFO_NAT_TYPE"_T,
get_nat_type_str(g_player_service->get_selected()->get_net_data()->m_nat_type))
.c_str());
if (auto peer = g_player_service->get_selected()->get_connection_peer()) if (auto peer = g_player_service->get_selected()->get_connection_peer())
{ {
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_CONNECTION_TYPE"_T, get_connection_type_str(peer->m_peer_address.m_connection_type)).c_str()); ImGui::Text(std::format("{}: {}",
"VIEW_PLAYER_INFO_CONNECTION_TYPE"_T,
get_connection_type_str(peer->m_peer_address.m_connection_type))
.c_str());
if (peer->m_peer_address.m_connection_type == 2) if (peer->m_peer_address.m_connection_type == 2)
{ {
auto ip = peer->m_relay_address.m_relay_address; auto ip = peer->m_relay_address.m_relay_address;
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str()); ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4)
} .c_str());
else if (peer->m_peer_address.m_connection_type == 3) }
{ else if (peer->m_peer_address.m_connection_type == 3)
auto ip = peer->m_peer_address.m_relay_address; {
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_PEER_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str()); auto ip = peer->m_peer_address.m_relay_address;
} ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_PEER_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4)
.c_str());
}
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_MESSAGES_SENT"_T, peer->m_num_messages_batched).c_str()); ImGui::Text(
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_SENT"_T, peer->m_num_reliable_messages_batched).c_str()); std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_MESSAGES_SENT"_T, peer->m_num_messages_batched).c_str());
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_RESENT"_T, peer->m_num_resent_reliable_messages_batched).c_str()); ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_SENT"_T, peer->m_num_reliable_messages_batched)
} .c_str());
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_RESENT"_T, peer->m_num_resent_reliable_messages_batched)
.c_str());
}
ImGui::Text(std::format("{}: {:X}", "VIEW_PLAYER_INFO_HOST_TOKEN"_T, g_player_service->get_selected()->get_net_data()->m_host_token).c_str()); ImGui::Text(std::format("{}: {:X}",
ImGui::SameLine(); "VIEW_PLAYER_INFO_HOST_TOKEN"_T,
if (ImGui::Button("Copy")) g_player_service->get_selected()->get_net_data()->m_host_token)
{ .c_str());
ImGui::SetClipboardText(std::format("{:X}", g_player_service->get_selected()->get_net_data()->m_host_token).data()); ImGui::SameLine();
} if (ImGui::Button("Copy"))
{
ImGui::SetClipboardText(
std::format("{:X}", g_player_service->get_selected()->get_net_data()->m_host_token).data());
}
ImGui::EndGroup(); ImGui::EndGroup();
ImGui::Separator(); ImGui::Separator();
if (ImGui::Checkbox("TRUST"_T.data(), &g_player_service->get_selected()->is_trusted)) if (ImGui::Checkbox("TRUST"_T.data(), &g_player_service->get_selected()->is_trusted))
{ {
auto entry = g_player_database_service->get_or_create_player(g_player_service->get_selected()); auto entry = g_player_database_service->get_or_create_player(g_player_service->get_selected());
entry->is_trusted = g_player_service->get_selected()->is_trusted; entry->is_trusted = g_player_service->get_selected()->is_trusted;
g_player_database_service->save(); g_player_database_service->save();
} }
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_EXPLOSIONS"_T.data(), &g_player_service->get_selected()->block_explosions); ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_EXPLOSIONS"_T.data(), &g_player_service->get_selected()->block_explosions);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_CREATE"_T.data(), &g_player_service->get_selected()->block_clone_create); ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_CREATE"_T.data(), &g_player_service->get_selected()->block_clone_create);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_SYNC"_T.data(), &g_player_service->get_selected()->block_clone_sync); ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_SYNC"_T.data(), &g_player_service->get_selected()->block_clone_sync);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_NETWORK_EVENTS"_T.data(), &g_player_service->get_selected()->block_net_events); ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_NETWORK_EVENTS"_T.data(), &g_player_service->get_selected()->block_net_events);
ImGui::Checkbox("VIEW_PLAYER_INFO_LOG_CLONES"_T.data(), &g_player_service->get_selected()->log_clones); ImGui::Checkbox("VIEW_PLAYER_INFO_LOG_CLONES"_T.data(), &g_player_service->get_selected()->log_clones);
ImGui::Separator(); ImGui::Separator();
if (ImGui::BeginCombo("CHAT_COMMAND_PERMISSIONS"_T.data(), if (ImGui::BeginCombo("CHAT_COMMAND_PERMISSIONS"_T.data(),
COMMAND_ACCESS_LEVELS[g_player_service->get_selected()->command_access_level.value_or( COMMAND_ACCESS_LEVELS[g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level)]))
g.session.chat_command_default_access_level)])) {
{ for (const auto& [type, name] : COMMAND_ACCESS_LEVELS)
for (const auto& [type, name] : COMMAND_ACCESS_LEVELS) {
{ if (ImGui::Selectable(name,
if (ImGui::Selectable(name, type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level)))
type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level))) {
{ g.session.chat_command_default_access_level = type;
g.session.chat_command_default_access_level = type; g_player_database_service->get_or_create_player(g_player_service->get_selected())->command_access_level = type;
g_player_database_service->get_or_create_player(g_player_service->get_selected())->command_access_level = type; g_player_database_service->save();
g_player_database_service->save(); }
}
if (type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level)) if (type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level))
{ {
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
} }
} }
ImGui::EndCombo(); ImGui::EndCombo();
} }
}, },
false, false,
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data()); "VIEW_PLAYER_INFO_EXTRA_INFO"_T.data());
ImGui::SameLine(); ImGui::SameLine();
@ -280,11 +297,11 @@ namespace big
if (ip) if (ip)
{ {
ImGui::Text("PLAYER_INFO_IP"_T.data(), ImGui::Text("PLAYER_INFO_IP"_T.data(),
ip.value().m_field1, ip.value().m_field1,
ip.value().m_field2, ip.value().m_field2,
ip.value().m_field3, ip.value().m_field3,
ip.value().m_field4, ip.value().m_field4,
port); port);
ImGui::SameLine(); ImGui::SameLine();
@ -308,8 +325,8 @@ namespace big
ImGui::Text("VIEW_PLAYER_INFO_IP_UNKNOWN"_T.data()); ImGui::Text("VIEW_PLAYER_INFO_IP_UNKNOWN"_T.data());
auto cxn_type = g_player_service->get_selected()->get_connection_peer() ? auto cxn_type = g_player_service->get_selected()->get_connection_peer() ?
g_player_service->get_selected()->get_connection_peer()->m_peer_address.m_connection_type : g_player_service->get_selected()->get_connection_peer()->m_peer_address.m_connection_type :
0; 0;
if (g.protections.force_relay_connections && ImGui::IsItemHovered()) if (g.protections.force_relay_connections && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_FORCE_RELAY_TOOLTIP"_T.data()); ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_FORCE_RELAY_TOOLTIP"_T.data());

View File

@ -27,20 +27,20 @@ namespace big
ImGui::EndCombo(); ImGui::EndCombo();
} }
if (ImGui::BeginCombo("VIEW_SETTINGS_GAME_LANGUAGE"_T.data(), languages[*g_pointers->m_gta.m_language].name)) if (ImGui::BeginCombo("VIEW_SETTINGS_GAME_LANGUAGE"_T.data(), languages.at(*g_pointers->m_gta.m_language).data()))
{ {
for (auto& language : languages) for (auto& [id, language] : languages)
{ {
if (ImGui::Selectable(language.name, language.id == *g_pointers->m_gta.m_language)) if (ImGui::Selectable(language.data(), id == *g_pointers->m_gta.m_language))
{ {
*g_pointers->m_gta.m_language = language.id; *g_pointers->m_gta.m_language = id;
g_fiber_pool->queue_job([] { g_fiber_pool->queue_job([] {
g_pointers->m_gta.m_update_language(true); g_pointers->m_gta.m_update_language(true);
}); });
} }
if (language.id == *g_pointers->m_gta.m_language) if (id == *g_pointers->m_gta.m_language)
{ {
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
} }