mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-01-04 00:23:27 +08:00
Player database improvements (#1705)
* feat(protections): add per-player sync block options * feat(player_database): improve player tracker * fix(rapid_fire): remove unnecessary log statement * fix(player_database): default state should be UNKNOWN, not INVALID
This commit is contained in:
parent
06cf2a579e
commit
71db1ca1fa
@ -20,8 +20,6 @@ namespace big
|
||||
if (!weapon_entity)
|
||||
return;
|
||||
|
||||
LOG(INFO) << weapon_entity;
|
||||
|
||||
Vector3 dim_min;
|
||||
Vector3 dim_max;
|
||||
MISC::GET_MODEL_DIMENSIONS(ENTITY::GET_ENTITY_MODEL(weapon_entity), &dim_min, &dim_max);
|
||||
@ -36,14 +34,15 @@ namespace big
|
||||
Vector3 end = camera_position + camera_direction * 2000.0;
|
||||
|
||||
const auto raycast_handle =
|
||||
SHAPETEST::START_EXPENSIVE_SYNCHRONOUS_SHAPE_TEST_LOS_PROBE(
|
||||
camera_position.x,
|
||||
SHAPETEST::START_EXPENSIVE_SYNCHRONOUS_SHAPE_TEST_LOS_PROBE(camera_position.x,
|
||||
camera_position.y,
|
||||
camera_position.z,
|
||||
end.x,
|
||||
end.y,
|
||||
end.z,
|
||||
-1, 0, 7);
|
||||
-1,
|
||||
0,
|
||||
7);
|
||||
int did_raycast_hit = 0;
|
||||
Vector3 raycast_hit_position{};
|
||||
Vector3 raycast_surface_normal_hit_position{};
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "services/gta_data/gta_data_service.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "services/gta_data/gta_data_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
const int input_array[6] = {(int)ControllerInputs::INPUT_SELECT_WEAPON_UNARMED, (int)ControllerInputs::INPUT_SELECT_WEAPON_MELEE, (int)ControllerInputs::INPUT_SELECT_WEAPON_SHOTGUN, (int)ControllerInputs::INPUT_SELECT_WEAPON_HEAVY, (int)ControllerInputs::INPUT_SELECT_WEAPON_SPECIAL, (int)ControllerInputs::INPUT_SELECT_WEAPON_HANDGUN};
|
||||
constexpr int input_array[6] = {(int)ControllerInputs::INPUT_SELECT_WEAPON_UNARMED, (int)ControllerInputs::INPUT_SELECT_WEAPON_MELEE, (int)ControllerInputs::INPUT_SELECT_WEAPON_SHOTGUN, (int)ControllerInputs::INPUT_SELECT_WEAPON_HEAVY, (int)ControllerInputs::INPUT_SELECT_WEAPON_SPECIAL, (int)ControllerInputs::INPUT_SELECT_WEAPON_HANDGUN};
|
||||
|
||||
static void resolve_weapon_hotkey(Hash weapon)
|
||||
{
|
||||
@ -37,7 +37,14 @@ namespace big
|
||||
PAD::DISABLE_CONTROL_ACTION(0, input_array[iterator_keys], FALSE);
|
||||
if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, input_array[iterator_keys]))
|
||||
{
|
||||
auto hotkey_vector = g.weapons.weapon_hotkeys[iterator_keys];
|
||||
if (!g.weapons.weapon_hotkeys.count(iterator_keys))
|
||||
continue;
|
||||
|
||||
auto& hotkey_vector = g.weapons.weapon_hotkeys[iterator_keys];
|
||||
|
||||
if (hotkey_vector.empty())
|
||||
continue;
|
||||
|
||||
Hash weapon_hash_to_select = hotkey_vector[0];
|
||||
for (auto vector_iterator = hotkey_vector.begin(); vector_iterator != hotkey_vector.end(); ++vector_iterator)
|
||||
{
|
||||
|
@ -230,9 +230,15 @@ namespace big
|
||||
|
||||
struct player_db
|
||||
{
|
||||
bool update_player_online_states = false;
|
||||
bool update_player_online_states = true;
|
||||
bool notify_when_online = false;
|
||||
bool notify_when_joinable = true;
|
||||
bool notify_when_unjoinable = false;
|
||||
bool notify_when_offline = false;
|
||||
bool notify_on_session_type_change = false;
|
||||
bool notify_on_session_change = false;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(player_db, update_player_online_states)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(player_db, update_player_online_states, notify_when_online, notify_when_joinable, notify_when_unjoinable, notify_when_offline, notify_on_session_type_change, notify_on_session_change)
|
||||
} player_db{};
|
||||
|
||||
struct protections
|
||||
|
@ -98,7 +98,7 @@ namespace big::functions
|
||||
using get_gamer_online_state = bool (*)(int profile_index, rage::rlGamerHandle* handles, std::uint32_t count, int* online_state, rage::rlTaskStatus* status);
|
||||
using start_get_session_by_gamer_handle = bool (*)(int profile_index, rage::rlGamerHandle* handles, int count, rage::rlSessionByGamerTaskResult* result, int unk, bool* success, rage::rlTaskStatus* state);
|
||||
using start_matchmaking_find_sessions = bool (*)(int profile_index, int available_slots, NetworkGameFilterMatchmakingComponent* m_filter, unsigned int max_sessions, rage::rlSessionInfo* result_sessions, int* result_session_count, rage::rlTaskStatus* state);
|
||||
using start_get_presence_attributes = bool (*)(int profile_index, rage::rlScHandle* handle, rage::rlQueryPresenceAttributesContext* contexts, int count, rage::rlTaskStatus* state);
|
||||
using start_get_presence_attributes = bool (*)(int profile_index, rage::rlScHandle* handle, int num_handles, rage::rlQueryPresenceAttributesContext** contexts, int count, rage::rlTaskStatus* state);
|
||||
using join_session_by_info = bool (*)(Network* network, rage::rlSessionInfo* info, int unk, int flags, rage::rlGamerHandle* handles, int handlecount);
|
||||
|
||||
using generate_uuid = bool (*)(std::uint64_t* uuid);
|
||||
|
@ -1948,3 +1948,19 @@ enum class eCombatAbilityLevel
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(eCombatAbilityLevel, {{eCombatAbilityLevel::POOR, "poor"}, {eCombatAbilityLevel::AVERAGE, "average"}, {eCombatAbilityLevel::PROFESSIONAL, "professional"}})
|
||||
|
||||
enum class GSType : int32_t
|
||||
{
|
||||
Unknown = -2,
|
||||
|
||||
// actual values start here
|
||||
Invalid = -1,
|
||||
InviteOnly,
|
||||
FriendsOnly,
|
||||
ClosedCrew,
|
||||
OpenCrew,
|
||||
Job,
|
||||
Public,
|
||||
Max,
|
||||
Modder = 69 // stand?
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
#include "hooking.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
|
||||
namespace big
|
||||
@ -11,6 +12,11 @@ namespace big
|
||||
return true;
|
||||
}
|
||||
|
||||
auto plyr = g_player_service->get_by_id(src->m_player_id);
|
||||
|
||||
if (plyr && plyr->block_clone_create)
|
||||
return true;
|
||||
|
||||
g.m_syncing_player = src;
|
||||
return g_hooking->get_original<hooks::received_clone_create>()(mgr, src, dst, object_type, object_id, object_flag, buffer, timestamp);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "hooking.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
|
||||
namespace big
|
||||
@ -17,6 +18,11 @@ namespace big
|
||||
return eAckCode::ACKCODE_FAIL;
|
||||
}
|
||||
|
||||
auto plyr = g_player_service->get_by_id(src->m_player_id);
|
||||
|
||||
if (plyr && plyr->block_clone_create)
|
||||
return eAckCode::ACKCODE_FAIL;
|
||||
|
||||
g.m_syncing_player = src;
|
||||
return g_hooking->get_original<received_clone_sync>()(mgr, src, dst, object_type, object_id, buffer, unk, timestamp);
|
||||
}
|
||||
|
@ -368,6 +368,12 @@ namespace big
|
||||
|
||||
auto plyr = g_player_service->get_by_id(source_player->m_player_id);
|
||||
|
||||
if (plyr && plyr->block_net_events)
|
||||
{
|
||||
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (static_cast<eNetworkEvents>(event_id))
|
||||
{
|
||||
case eNetworkEvents::KICK_VOTES_EVENT:
|
||||
|
@ -1389,7 +1389,7 @@ namespace big
|
||||
// Start Get Presence Attributes
|
||||
{
|
||||
"SGPA",
|
||||
"48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 54 41 56 41 57 48 83 EC 40 33 DB 41",
|
||||
"48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 54 41 56 41 57 48 83 EC 40 33 DB 49",
|
||||
[](memory::handle ptr)
|
||||
{
|
||||
g_pointers->m_sc.m_start_get_presence_attributes = ptr.as<functions::start_get_presence_attributes>();
|
||||
|
@ -35,15 +35,10 @@ namespace nlohmann
|
||||
};
|
||||
}
|
||||
|
||||
enum class GSType : int32_t;
|
||||
|
||||
namespace big
|
||||
{
|
||||
enum class PlayerOnlineStatus
|
||||
{
|
||||
UNKNOWN,
|
||||
OFFLINE,
|
||||
ONLINE
|
||||
};
|
||||
|
||||
struct persistent_player
|
||||
{
|
||||
std::string name;
|
||||
@ -55,7 +50,8 @@ namespace big
|
||||
std::unordered_set<int> infractions;
|
||||
std::string notes = "";
|
||||
std::optional<CommandAccessLevel> command_access_level = std::nullopt;
|
||||
PlayerOnlineStatus online_state = PlayerOnlineStatus::UNKNOWN;
|
||||
GSType session_type = GSType(-2);
|
||||
int64_t session_id = -1;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, name, rockstar_id, block_join, block_join_reason, is_modder, notify_online, infractions, notes, command_access_level)
|
||||
};
|
||||
|
@ -2,14 +2,43 @@
|
||||
|
||||
#include "backend/bool_command.hpp"
|
||||
#include "file_manager.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "util/session.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool_command g_player_db_auto_update_online_states("player_db_auto_update_states", "Auto Update Player Online States", "Toggling this feature will automatically update the player online states every 5minutes.",
|
||||
bool_command g_player_db_auto_update_online_states("player_db_auto_update_states", "Auto Update Tracked Player States", "Toggling this feature will automatically update the tracked players' online states every minute",
|
||||
g.player_db.update_player_online_states);
|
||||
|
||||
void player_database_service::handle_session_type_change(persistent_player& player, GSType new_session_type)
|
||||
{
|
||||
if (!player.notify_online)
|
||||
return;
|
||||
|
||||
if (g.player_db.notify_when_joinable && !is_joinable_session(player.session_type) && is_joinable_session(new_session_type))
|
||||
{
|
||||
g_notification_service->push_success("Player DB", std::format("{} is now in a joinable session", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_online && (player.session_type == GSType::Invalid || player.session_type == GSType::Unknown) && new_session_type != GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push_success("Player DB", std::format("{} is now online", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_unjoinable && is_joinable_session(player.session_type) && !is_joinable_session(new_session_type) && new_session_type != GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is no longer in a joinable session", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_offline && player.session_type != GSType::Invalid && player.session_type != GSType::Unknown && new_session_type == GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is no longer online", player.name));
|
||||
}
|
||||
|
||||
if (g.player_db.notify_on_session_type_change && (int)new_session_type >= (int)GSType::InviteOnly && (int)new_session_type < (int)GSType::Max)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is now in a{} {} session", player.name, new_session_type == GSType::InviteOnly ? "n" : "", get_session_type_str(new_session_type)));
|
||||
}
|
||||
}
|
||||
|
||||
player_database_service::player_database_service() :
|
||||
m_file_path(g_file_manager.get_project_file("./players.json").get_path())
|
||||
{
|
||||
@ -150,14 +179,14 @@ namespace big
|
||||
return;
|
||||
|
||||
g_thread_pool->push([this] {
|
||||
static auto last_update = std::chrono::high_resolution_clock::now() - 5min;
|
||||
static auto last_update = std::chrono::high_resolution_clock::now() - 45s;
|
||||
while (g_running && g.player_db.update_player_online_states)
|
||||
{
|
||||
const auto cur = std::chrono::high_resolution_clock::now();
|
||||
if (cur - last_update > 5min)
|
||||
if (cur - last_update > 45s)
|
||||
{
|
||||
g_fiber_pool->queue_job([this] {
|
||||
update_player_states();
|
||||
update_player_states(true);
|
||||
});
|
||||
last_update = cur;
|
||||
}
|
||||
@ -167,52 +196,105 @@ namespace big
|
||||
});
|
||||
}
|
||||
|
||||
void player_database_service::update_player_states()
|
||||
void player_database_service::update_player_states(bool tracked_only)
|
||||
{
|
||||
const auto player_count = m_players.size();
|
||||
const auto player_count = m_players.size();
|
||||
constexpr auto bucket_size = 100;
|
||||
|
||||
std::vector<std::vector<rage::rlGamerHandle>> gamer_handle_buckets;
|
||||
gamer_handle_buckets.resize(std::ceil(player_count / 32.f));
|
||||
std::vector<std::vector<rage::rlScHandle>> gamer_handle_buckets;
|
||||
gamer_handle_buckets.resize(std::ceil(player_count / (float)bucket_size));
|
||||
|
||||
auto it = m_players.begin();
|
||||
for (size_t i = 0; i < player_count; ++i)
|
||||
size_t i = 0;
|
||||
for (auto& player : m_players)
|
||||
{
|
||||
gamer_handle_buckets[i / 32].push_back(it->second->rockstar_id);
|
||||
|
||||
it++;
|
||||
if (!tracked_only || player.second->notify_online)
|
||||
{
|
||||
gamer_handle_buckets[i / bucket_size].push_back(player.second->rockstar_id);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
return;
|
||||
|
||||
for (auto& bucket : gamer_handle_buckets)
|
||||
{
|
||||
rage::rlTaskStatus status;
|
||||
std::array<int, 32> online;
|
||||
rage::rlTaskStatus status{};
|
||||
rage::rlQueryPresenceAttributesContext contexts[bucket_size][2]{};
|
||||
rage::rlQueryPresenceAttributesContext* contexts_per_player[bucket_size]{};
|
||||
|
||||
if (g_pointers->m_gta.m_get_gamer_online_state(0, bucket.data(), bucket.size(), online.data(), &status))
|
||||
for (int i = 0; i < bucket_size; i++)
|
||||
{
|
||||
contexts[i][0].m_presence_attibute_type = 3;
|
||||
strcpy(contexts[i][0].m_presence_attribute_key, "gstype");
|
||||
strcpy(contexts[i][0].m_presence_attribute_value, "-1");
|
||||
contexts[i][1].m_presence_attibute_type = 3;
|
||||
strcpy(contexts[i][1].m_presence_attribute_key, "gsinfo");
|
||||
contexts_per_player[i] = contexts[i];
|
||||
}
|
||||
|
||||
if (g_pointers->m_sc.m_start_get_presence_attributes(0, bucket.data(), bucket.size(), contexts_per_player, 2, &status))
|
||||
{
|
||||
while (status.status == 1)
|
||||
{
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < bucket.size(); ++i)
|
||||
if (status.status == 3)
|
||||
{
|
||||
if (const auto& it = m_players.find(bucket[i].m_rockstar_id); it != m_players.end())
|
||||
for (size_t i = 0; i < bucket.size(); ++i)
|
||||
{
|
||||
if (online[i] == 1)
|
||||
if (const auto& it = m_players.find(bucket[i].m_rockstar_id); it != m_players.end())
|
||||
{
|
||||
if (it->second->online_state == PlayerOnlineStatus::OFFLINE && it->second->notify_online)
|
||||
{
|
||||
g_notification_service->push_success("Player DB",
|
||||
std::format("{} is now online!", it->second->name));
|
||||
}
|
||||
it->second->online_state = PlayerOnlineStatus::ONLINE;
|
||||
rage::rlSessionInfo info{};
|
||||
info.m_session_token = -1;
|
||||
GSType gstype = (GSType)atoi(contexts[i][0].m_presence_attribute_value);
|
||||
|
||||
continue;
|
||||
if (!g_pointers->m_gta.m_decode_session_info(&info, contexts[i][1].m_presence_attribute_value, nullptr))
|
||||
gstype = GSType::Invalid;
|
||||
|
||||
if (it->second->session_type != gstype)
|
||||
{
|
||||
handle_session_type_change(*it->second, gstype);
|
||||
}
|
||||
else if (it->second->notify_online && it->second->session_id != info.m_session_token)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
std::format("{} has joined a new session", it->second->name));
|
||||
}
|
||||
|
||||
it->second->session_type = gstype;
|
||||
it->second->session_id = info.m_session_token;
|
||||
}
|
||||
it->second->online_state = PlayerOnlineStatus::OFFLINE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(WARNING) << "Presence attribute endpoint failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool player_database_service::is_joinable_session(GSType type)
|
||||
{
|
||||
return type == GSType::Public || type == GSType::OpenCrew;
|
||||
}
|
||||
|
||||
const char* player_database_service::get_session_type_str(GSType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GSType::Invalid: return "Offline";
|
||||
case GSType::InviteOnly: return "Invite Only";
|
||||
case GSType::FriendsOnly: return "Friends Only";
|
||||
case GSType::ClosedCrew: return "Closed Crew";
|
||||
case GSType::OpenCrew: return "Crew";
|
||||
case GSType::Job: return "In Mission";
|
||||
case GSType::Public: return "Public";
|
||||
case GSType::Modder: return "Unknown (Concealed By Modder)";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace nlohmann
|
||||
|
||||
static void from_json(const json& j, std::shared_ptr<T>& value)
|
||||
{
|
||||
value = std::make_shared<T>();
|
||||
value = std::make_shared<T>();
|
||||
*value = j.get<T>();
|
||||
}
|
||||
};
|
||||
@ -28,6 +28,8 @@ namespace big
|
||||
std::map<std::string, std::shared_ptr<persistent_player>> m_sorted_players;
|
||||
std::shared_ptr<persistent_player> m_selected = nullptr;
|
||||
|
||||
void handle_session_type_change(persistent_player& player, GSType new_session_type);
|
||||
|
||||
public:
|
||||
std::filesystem::path m_file_path;
|
||||
player_database_service();
|
||||
@ -46,9 +48,12 @@ namespace big
|
||||
|
||||
void set_selected(std::shared_ptr<persistent_player> selected);
|
||||
std::shared_ptr<persistent_player> get_selected();
|
||||
|
||||
|
||||
void start_update_loop();
|
||||
void update_player_states();
|
||||
void update_player_states(bool tracked_only = false);
|
||||
|
||||
static bool is_joinable_session(GSType type);
|
||||
static const char* get_session_type_str(GSType type);
|
||||
};
|
||||
|
||||
inline player_database_service* g_player_database_service;
|
||||
|
@ -83,7 +83,12 @@ namespace big
|
||||
std::optional<std::uint32_t> time_difference;
|
||||
std::uint32_t num_time_syncs_sent = 9999;
|
||||
|
||||
bool block_explosions = false;
|
||||
bool block_explosions = false;
|
||||
bool block_clone_create = false;
|
||||
bool block_clone_sync = false;
|
||||
bool block_net_events = false;
|
||||
bool log_clones = false;
|
||||
bool log_network_events = false;
|
||||
|
||||
int spectating_player = -1;
|
||||
|
||||
|
@ -11,6 +11,8 @@ namespace
|
||||
"www.",
|
||||
".cn",
|
||||
".CN",
|
||||
".cc",
|
||||
".CC",
|
||||
".TOP",
|
||||
".COM",
|
||||
".top",
|
||||
@ -25,8 +27,6 @@ namespace
|
||||
"doit#",
|
||||
"krutka#",
|
||||
"<b>",
|
||||
// causes false positives for people typing in cyrillic
|
||||
// "\xD0\xBC\xD0\xB5", // Cyrillic "me"
|
||||
"P888",
|
||||
"gtacash",
|
||||
"\xE6\x89\xA3\xE6\x89\xA3", // no clue what this is
|
||||
@ -39,21 +39,22 @@ namespace
|
||||
"REP +",
|
||||
"20R$", // Brazil currency?
|
||||
"l55.me",
|
||||
"\xE5\xBA\x97", //"shop" in Chinese
|
||||
"\xE9\x92\xB1", //"money" in Chinese
|
||||
"\xE5\x88\xB7", //"make(money)" in Chinese
|
||||
// disabled as it's too verbose
|
||||
// "av", //uknowwhat video
|
||||
"\xE8\x90\x9D\xE8\x8E\x89", //"cute girl" in Chinese
|
||||
"\xE5\xA6\x88", //"mother" in Chinese
|
||||
"\xE7\xBE\x8E\xE5\xA5\xB3", //"sexy girl" in Chinese
|
||||
"\xE5\xBC\xBA\xE5\xA5\xB8", //"rape" in Chinese
|
||||
"\xE8\x90\x9D", //"loli" in Chinese
|
||||
"\xE6\x8C\x82", //"hack" in Chinese
|
||||
"\xE5\x85\x83", //chinese dollar
|
||||
"\xE5\xBA\x97", //"shop" in Chinese
|
||||
"\xE9\x92\xB1", //"money" in Chinese
|
||||
"\xE5\x88\xB7", //"make(money)" in Chinese
|
||||
"\xE8\x90\x9D\xE8\x8E\x89", // "cute girl" in Chinese
|
||||
"\xE5\xA6\x88", // "mother" in Chinese
|
||||
"\xE7\xBE\x8E\xE5\xA5\xB3", // "sexy girl" in Chinese
|
||||
"\xE5\xBC\xBA\xE5\xA5\xB8", // "rape" in Chinese
|
||||
"\xE8\x90\x9D", // "loli" in Chinese
|
||||
"\xE6\x8C\x82", // "hack" in Chinese
|
||||
"\xE5\x85\x83", // chinese dollar
|
||||
"\xE9\x98\xB4\xE4\xBC\xA0\xE5\xAA\x92", // "Yin Media" in Chinese
|
||||
"\xE7\xBD\x91\xE7\xBA\xA2", // "internet celebrities" in Chinese
|
||||
"TRUSTPILOT",
|
||||
"cashlounge",
|
||||
"Fast Delivery",
|
||||
"yosativa",
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,7 @@ namespace big
|
||||
global_test.global_appendages.clear();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
@ -47,8 +47,10 @@ namespace big
|
||||
ImGui::SameLine();
|
||||
components::button("JOIN_SESSION_INFO"_T, [] {
|
||||
rage::rlSessionInfo info;
|
||||
g_pointers->m_gta.m_decode_session_info(&info, base64, nullptr);
|
||||
session::join_session(info);
|
||||
if (g_pointers->m_gta.m_decode_session_info(&info, base64, nullptr))
|
||||
session::join_session(info);
|
||||
else
|
||||
g_notification_service->push_error("Join", "Session info is invalid");
|
||||
});
|
||||
|
||||
components::button("COPY_SESSION_INFO"_T, [] {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "core/data/command_access_levels.hpp"
|
||||
#include "core/data/infractions.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/api/api_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
@ -17,6 +18,18 @@ namespace big
|
||||
bool notes_dirty = false;
|
||||
std::shared_ptr<persistent_player> current_player;
|
||||
|
||||
ImVec4 get_player_color(persistent_player& player)
|
||||
{
|
||||
if (player.session_type == GSType::Unknown)
|
||||
return ImVec4(.5f, .5f, .5f, 1.0f);
|
||||
else if (player.session_type == GSType::Invalid)
|
||||
return ImVec4(1.f, 0.f, 0.f, 1.f);
|
||||
else if (!player_database_service::is_joinable_session(player.session_type))
|
||||
return ImVec4(1.f, 1.f, 0.f, 1.f);
|
||||
else
|
||||
return ImVec4(0.f, 1.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
void draw_player_db_entry(std::shared_ptr<persistent_player> player, const std::string& lower_search)
|
||||
{
|
||||
std::string name = player->name;
|
||||
@ -28,15 +41,9 @@ namespace big
|
||||
|
||||
float circle_size = 7.5f;
|
||||
auto cursor_pos = ImGui::GetCursorScreenPos();
|
||||
auto plyr_state = player->online_state;
|
||||
|
||||
//render status circle
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(ImVec2(cursor_pos.x + 4.f + circle_size, cursor_pos.y + 4.f + circle_size),
|
||||
circle_size,
|
||||
ImColor(plyr_state == PlayerOnlineStatus::ONLINE ? ImVec4(0.f, 1.f, 0.f, 1.f) :
|
||||
plyr_state == PlayerOnlineStatus::OFFLINE ? ImVec4(1.f, 0.f, 0.f, 1.f) :
|
||||
plyr_state == PlayerOnlineStatus::UNKNOWN ? ImVec4(.5f, .5f, .5f, 1.0f) :
|
||||
ImVec4(.5f, .5f, .5f, 1.0f)));
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(ImVec2(cursor_pos.x + 4.f + circle_size, cursor_pos.y + 4.f + circle_size), circle_size, ImColor(get_player_color(*player)));
|
||||
|
||||
//we need some padding
|
||||
ImVec2 cursor = ImGui::GetCursorPos();
|
||||
@ -57,6 +64,9 @@ namespace big
|
||||
strncpy(note_buffer, current_player->notes.data(), sizeof(note_buffer));
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip(player_database_service::get_session_type_str(player->session_type));
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
@ -76,13 +86,20 @@ namespace big
|
||||
|
||||
for (auto& player : item_arr | std::ranges::views::values)
|
||||
{
|
||||
if (player->online_state == PlayerOnlineStatus::ONLINE)
|
||||
if (player_database_service::is_joinable_session(player->session_type))
|
||||
draw_player_db_entry(player, lower_search);
|
||||
}
|
||||
|
||||
for (auto& player : item_arr | std::ranges::views::values)
|
||||
{
|
||||
if (player->online_state != PlayerOnlineStatus::ONLINE)
|
||||
if (!player_database_service::is_joinable_session(player->session_type) && player->session_type != GSType::Invalid
|
||||
&& player->session_type != GSType::Unknown)
|
||||
draw_player_db_entry(player, lower_search);
|
||||
}
|
||||
|
||||
for (auto& player : item_arr | std::ranges::views::values)
|
||||
{
|
||||
if (player->session_type == GSType::Invalid || player->session_type == GSType::Unknown)
|
||||
draw_player_db_entry(player, lower_search);
|
||||
}
|
||||
}
|
||||
@ -107,7 +124,7 @@ namespace big
|
||||
if (ImGui::InputScalar("RID"_T.data(), ImGuiDataType_S64, ¤t_player->rockstar_id)
|
||||
|| ImGui::Checkbox("IS_MODDER"_T.data(), ¤t_player->is_modder)
|
||||
|| ImGui::Checkbox("BLOCK_JOIN"_T.data(), ¤t_player->block_join)
|
||||
|| ImGui::Checkbox("Notify When Online", ¤t_player->notify_online))
|
||||
|| ImGui::Checkbox("Track Player", ¤t_player->notify_online))
|
||||
{
|
||||
if (current_player->rockstar_id != selected->rockstar_id)
|
||||
g_player_database_service->update_rockstar_id(selected->rockstar_id, current_player->rockstar_id);
|
||||
@ -212,10 +229,28 @@ namespace big
|
||||
|
||||
if (ImGui::Button("REMOVE_ALL"_T.data()))
|
||||
{
|
||||
g_player_database_service->set_selected(nullptr);
|
||||
g_player_database_service->get_players().clear();
|
||||
g_player_database_service->get_sorted_players().clear();
|
||||
g_player_database_service->save();
|
||||
ImGui::OpenPopup("##removeall");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("##removeall"))
|
||||
{
|
||||
ImGui::Text("Are you sure?");
|
||||
|
||||
if (ImGui::Button("Yes"))
|
||||
{
|
||||
g_player_database_service->set_selected(nullptr);
|
||||
g_player_database_service->get_players().clear();
|
||||
g_player_database_service->get_sorted_players().clear();
|
||||
g_player_database_service->save();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("No"))
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
@ -224,8 +259,18 @@ namespace big
|
||||
g_player_database_service->update_player_states();
|
||||
});
|
||||
|
||||
if (components::command_checkbox<"player_db_auto_update_states">())
|
||||
g_player_database_service->start_update_loop();
|
||||
if (ImGui::TreeNode("Player Tracking"))
|
||||
{
|
||||
if (components::command_checkbox<"player_db_auto_update_states">("Enable"))
|
||||
g_player_database_service->start_update_loop();
|
||||
ImGui::Checkbox("Notify When Online", &g.player_db.notify_when_online);
|
||||
ImGui::Checkbox("Notify When Joinable", &g.player_db.notify_when_joinable);
|
||||
ImGui::Checkbox("Notify When Unjoinable", &g.player_db.notify_when_unjoinable);
|
||||
ImGui::Checkbox("Notify When Offline", &g.player_db.notify_when_offline);
|
||||
ImGui::Checkbox("Notify On Session Type Change", &g.player_db.notify_on_session_type_change);
|
||||
ImGui::Checkbox("Notify On Session Change", &g.player_db.notify_on_session_change);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
components::sub_title("NEW_ENTRY"_T);
|
||||
@ -244,7 +289,7 @@ namespace big
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("SEARCH"_T.data()))
|
||||
{
|
||||
g_thread_pool->push([]{
|
||||
g_thread_pool->push([] {
|
||||
if (!g_api_service->get_rid_from_username(new_name, *(uint64_t*)&new_rockstar_id))
|
||||
{
|
||||
g_notification_service->push_error("New Player DB Entry", std::format("No user '{}' called could be found.", new_name));
|
||||
|
@ -40,11 +40,11 @@ namespace big
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
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& 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;
|
||||
|
||||
const auto money = reinterpret_cast<uint64_t&>(stats.Money);
|
||||
const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance);
|
||||
const auto money = reinterpret_cast<uint64_t&>(stats.Money);
|
||||
const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance);
|
||||
|
||||
if (boss_goon.Language >= 0 && boss_goon.Language < 13)
|
||||
ImGui::Text("PLAYER_INFO_LANGUAGE"_T.data(), languages[boss_goon.Language].name);
|
||||
@ -69,6 +69,11 @@ namespace big
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Block Explosions", &g_player_service->get_selected()->block_explosions);
|
||||
ImGui::Checkbox("Block Clone Creates", &g_player_service->get_selected()->block_clone_create);
|
||||
ImGui::Checkbox("Block Clone Syncs", &g_player_service->get_selected()->block_clone_sync);
|
||||
ImGui::Checkbox("Block Network Events", &g_player_service->get_selected()->block_net_events);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::BeginCombo("CHAT_COMMAND_PERMISSIONS"_T.data(),
|
||||
COMMAND_ACCESS_LEVELS[g_player_service->get_selected()->command_access_level.value_or(
|
||||
|
@ -3,12 +3,12 @@
|
||||
#include "core/data/special_ammo_types.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "gta/joaat.hpp"
|
||||
#include "gta/weapons.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/gta_data/gta_data_service.hpp"
|
||||
#include "views/view.hpp"
|
||||
#include "services/persist_weapons/persist_weapons.hpp"
|
||||
#include "gta/weapons.hpp"
|
||||
#include "views/view.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -274,7 +274,7 @@ namespace big
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Persist Weapons"))
|
||||
{
|
||||
ImGui::Checkbox("Enabled", &g.persist_weapons.enabled);
|
||||
ImGui::Checkbox("Enabled##persist_weapons", &g.persist_weapons.enabled);
|
||||
|
||||
static std::string selected_loadout = g.persist_weapons.weapon_loadout_file;
|
||||
ImGui::PushItemWidth(250);
|
||||
@ -311,14 +311,14 @@ namespace big
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Weapon Hotkeys"))
|
||||
{
|
||||
ImGui::Checkbox("Enabled", &g.weapons.enable_weapon_hotkeys);
|
||||
ImGui::Checkbox("Enabled##weapon_hotkeys", &g.weapons.enable_weapon_hotkeys);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("This will select the next weapon in the hotkey list.\r\nThe first weapon in the list is the first weapon it will select, then the second is the one it will select after and so on.\r\nAfter the end of the list, it will wrap back to the first weapon.");
|
||||
}
|
||||
|
||||
static int selected_key = 0;
|
||||
const char* const keys[]{ "1", "2", "3", "4", "5", "6" };
|
||||
const char* const keys[]{"1", "2", "3", "4", "5", "6"};
|
||||
|
||||
ImGui::PushItemWidth(250);
|
||||
ImGui::Combo("Key", &selected_key, keys, IM_ARRAYSIZE(keys));
|
||||
|
Loading…
x
Reference in New Issue
Block a user