feat(PlayerList): Rewrite of entire player management system

This commit is contained in:
Yimura 2022-01-31 18:27:35 +01:00
parent ae57353d3f
commit 37e9e36713
No known key found for this signature in database
GPG Key ID: 3D8FF4397E768682
25 changed files with 305 additions and 285 deletions

View File

@ -14,7 +14,6 @@ namespace big
QUEUE_JOB_BEGIN_CLAUSE() QUEUE_JOB_BEGIN_CLAUSE()
{ {
looped::system_screen_size(); looped::system_screen_size();
looped::system_update_players();
looped::system_update_pointers(); looped::system_update_pointers();
}QUEUE_JOB_END_CLAUSE }QUEUE_JOB_END_CLAUSE

View File

@ -1,6 +1,7 @@
#include "backend/looped/looped.hpp" #include "backend/looped/looped.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "services/player_service.hpp"
namespace big namespace big
{ {
@ -8,7 +9,7 @@ namespace big
void looped::player_specate() void looped::player_specate()
{ {
if (!g.selected_player.is_online || !g.player.spectating) if (g_player_service->m_selected_player == nullptr || !g.player.spectating)
{ {
if (g.player.spectating) g.player.spectating = false; if (g.player.spectating) g.player.spectating = false;
@ -23,7 +24,7 @@ namespace big
return; return;
} }
Ped target = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g.selected_player.id); Ped target = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->m_selected_player->id());
g_pointers->m_spectate_player(true, target); g_pointers->m_spectate_player(true, target);
HUD::SET_MINIMAP_IN_SPECTATOR_MODE(true, target); HUD::SET_MINIMAP_IN_SPECTATOR_MODE(true, target);

View File

@ -1,63 +0,0 @@
#include "backend/looped/looped.hpp"
#include "natives.hpp"
#include "pointers.hpp"
#include "script.hpp"
#include "util/notify.hpp"
namespace big
{
static bool busy = false;
void looped::system_update_players()
{
if (busy) return;
busy = true;
for (Player i = 0; i < 32; i++)
{
CPlayer& player = g.players[i];
if (NETWORK::NETWORK_IS_PLAYER_ACTIVE(i))
{
strcpy(g.players[i].name, PLAYER::GET_PLAYER_NAME(i));
player.net_player = g_pointers->m_get_net_game_player(i);
if (player.is_online)
continue;
player.id = i;
player.is_online = true;
int iNetworkHandle[13];
NETWORK::NETWORK_HANDLE_FROM_PLAYER(i, iNetworkHandle, 13);
bool is_friend = NETWORK::NETWORK_IS_HANDLE_VALID(&iNetworkHandle[0], 13) && NETWORK::NETWORK_IS_FRIEND(&iNetworkHandle[0]);
if (is_friend)
{
player.is_friend = true;
g.friend_count++;
}
else g.player_count++;
notify::player_joined(player);
}
else if (player.is_online)
{
if (player.is_friend) g.friend_count--;
else g.player_count--;
player.is_friend = false;
player.is_online = false;
}
script::get_current()->yield();
}
if (g.window.player) // update selected player only while the player menu is open
g.selected_player = g.players[g.selected_player.id];
busy = false;
}
}

View File

@ -1,34 +0,0 @@
#pragma once
#include "CNetGamePlayer.hpp"
#ifndef PLAYER_STRUCT
#define PLAYER_STRUCT
namespace big
{
struct CPlayer
{
int32_t id;
char name[20];
bool is_friend = false;
bool is_online = false;
CNetGamePlayer* net_player;
bool operator < (const CPlayer& another) const
{
char temp[20], temp2[20];
for (uint8_t i = 0; i < 20; i++)
{
temp[i] = tolower(this->name[i]);
temp2[i] = tolower(another.name[i]);
}
return strcmp(temp, temp2) < 0;
}
};
}
#endif

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "data/player_struct.hpp"
#include "enums.hpp" #include "enums.hpp"
#ifndef GLOBALS_H #ifndef GLOBALS_H
@ -133,8 +132,6 @@ struct globals {
int friend_count = 0; int friend_count = 0;
int player_count = 0; int player_count = 0;
CPlayer players[32];
CPlayer selected_player;
debug debug{}; debug debug{};
tunables tunables{}; tunables tunables{};

View File

@ -5,59 +5,7 @@
#include "vector.hpp" #include "vector.hpp"
#include "gta\natives.hpp" #include "gta\natives.hpp"
#pragma pack(push, 1)
namespace rage
{
class netPlayerMgrBase
{
public:
virtual ~netPlayerMgrBase() = default; // 0 (0x00)
};
}
namespace gta namespace gta
{ {
inline constexpr auto num_players = 32; inline constexpr auto num_players = 32;
} }
//class CPlayerInfo : public rage::fwExtensibleBase
//{
//public:
// char pad_0020[20]; //0x0020
// uint32_t m_internal_ip; //0x0034
// uint16_t m_internal_port; //0x0038
// char pad_003A[2]; //0x003A
// uint32_t m_relay_ip; //0x003C
// uint16_t m_relay_port; //0x0040
// char pad_0042[2]; //0x0042
// uint32_t m_external_ip; //0x0044
// uint16_t m_external_port; //0x0048
// char pad_004A[38]; //0x004A
// uint64_t m_rockstar_id; //0x0070
// char pad_0078[12]; //0x0078
// char m_name[20]; //0x0084
// char pad_0098[180]; //0x0098
// float m_swim_speed; //0x014C
// float m_run_speed; //0x0150
// char pad_0154[81]; //0x0154
// bool m_is_rockstar_dev; //0x01A5
// char pad_01A6[1]; //0x01A6
// bool m_is_cheater; //0x01A7
// char pad_01A8[11]; //0x01A8
// bool m_is_online; //0x01B3
// char pad_01B4[20]; //0x01B4
// class CPed* m_ped; //0x01C8
// char pad_01D0[40]; //0x01D0
// uint32_t m_frame_flags; //0x01F8
// char pad_01FC[28]; //0x01FC
// uint32_t m_player_controls; //0x0218
// char pad_021C[1604]; //0x021C
// bool m_is_wanted; //0x0860
// char pad_0861[3]; //0x0861
// int8_t m_wanted_level_display; //0x0864
// char pad_0865[3]; //0x0865
// int8_t m_wanted_level; //0x0868
//}; //Size: 0x0869
//static_assert(sizeof(CPlayerInfo) == 0x869);
#pragma pack(pop)

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "common.hpp"
#include "gta/array.hpp" #include "gta/array.hpp"
#include "CPedFactory.hpp" #include "CPedFactory.hpp"
#include "gta/player.hpp" #include "CNetworkPlayerMgr.hpp"
#include "gta/script_thread.hpp" #include "gta/script_thread.hpp"
#include "gta/tls_context.hpp" #include "gta/tls_context.hpp"
#include "pointers.hpp" #include "pointers.hpp"
@ -32,6 +31,11 @@ namespace big::gta_util
return nullptr; return nullptr;
} }
inline CNetworkPlayerMgr* get_network_player_mgr()
{
return *g_pointers->m_network_player_mgr;
}
template <typename F, typename ...Args> template <typename F, typename ...Args>
void execute_as_script(rage::joaat_t script_hash, F &&callback, Args &&...args) void execute_as_script(rage::joaat_t script_hash, F &&callback, Args &&...args)
{ {

View File

@ -9,7 +9,7 @@ namespace big
static void handling(); static void handling();
static void log(); static void log();
static void main(); static void main();
static void player(); static void w_player();
static void users(); static void users();
public: public:
@ -24,7 +24,7 @@ namespace big
window::main(); window::main();
window::handling(); window::handling();
window::player(); window::w_player();
window::users(); window::users();
} }
}; };

View File

@ -11,31 +11,35 @@ namespace big
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Player ID: %d", g.selected_player.id); ImGui::Text("Player ID: %d", g_player_service->m_selected_player->id());
ImGui::Text("Session Host: %s", g_player_service->m_selected_player->is_host() ? "Yes" : "No");
if (CNetGamePlayer* net_player = g.selected_player.net_player; net_player != nullptr)
{
if (CPlayerInfo* player_info = net_player->m_player_info; player_info != nullptr)
{
rage::netPlayerData& netData = player_info->m_net_player_data;
ImGui::Text("Session Host: %s", net_player->is_host() ? "Yes" : "No");
ImGui::Separator(); ImGui::Separator();
if (CPlayerInfo* player_info = g_player_service->m_selected_player->get_player_info(); player_info != nullptr)
{
ImGui::Text("Wanted Level: %d", player_info->m_wanted_level); ImGui::Text("Wanted Level: %d", player_info->m_wanted_level);
ImGui::Text("Player God Mode: %s", misc::has_bit_set((int*)&player_info->m_ped->m_damage_bits, 8) ? "Yes" : "No"); ImGui::Text("Player God Mode: %s", misc::has_bit_set((int*)&player_info->m_ped->m_damage_bits, 8) ? "Yes" : "No");
ImGui::Text("Vehicle God Mode: %s", ImGui::Text("Vehicle God Mode: %s",
player_info->m_ped->m_vehicle == nullptr ? "No vehicle detected" : player_info->m_ped->m_vehicle == nullptr ? "No vehicle detected" :
misc::has_bit_set((int*)&player_info->m_ped->m_vehicle->m_damage_bits, 8) ? "Yes" : "No" misc::has_bit_set((int*)&player_info->m_ped->m_vehicle->m_damage_bits, 8) ? "Yes" : "No"
); );
}
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Rockstar ID: %d", netData.m_rockstar_id); if (rage::netPlayerData* net_player_data = g_player_service->m_selected_player->get_net_data(); net_player_data != nullptr)
ImGui::Text("IP Address: %d.%d.%d.%d:%d", netData.m_external_ip.m_field1, netData.m_external_ip.m_field2, netData.m_external_ip.m_field3, netData.m_external_ip.m_field4, netData.m_external_port); {
} ImGui::Text("Rockstar ID: %d", net_player_data->m_rockstar_id);
ImGui::Text(
"IP Address: %d.%d.%d.%d:%d",
net_player_data->m_external_ip.m_field1,
net_player_data->m_external_ip.m_field2,
net_player_data->m_external_ip.m_field3,
net_player_data->m_external_ip.m_field4,
net_player_data->m_external_port
);
} }
ImGui::EndTabItem(); ImGui::EndTabItem();

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "common.hpp"
#include "imgui.h" #include "imgui.h"
#include "services/player_service.hpp"
namespace big::tab_player namespace big::tab_player
{ {

View File

@ -12,7 +12,7 @@ namespace big
{ {
QUEUE_JOB_BEGIN_CLAUSE() QUEUE_JOB_BEGIN_CLAUSE()
{ {
teleport::to_player(g.selected_player.id); teleport::to_player(g_player_service->m_selected_player->id());
}QUEUE_JOB_END_CLAUSE }QUEUE_JOB_END_CLAUSE
} }
@ -21,7 +21,7 @@ namespace big
{ {
QUEUE_JOB_BEGIN_CLAUSE() QUEUE_JOB_BEGIN_CLAUSE()
{ {
teleport::bring_player(g.selected_player.id); teleport::bring_player(g_player_service->m_selected_player->id());
}QUEUE_JOB_END_CLAUSE }QUEUE_JOB_END_CLAUSE
} }
@ -29,7 +29,7 @@ namespace big
{ {
QUEUE_JOB_BEGIN_CLAUSE() QUEUE_JOB_BEGIN_CLAUSE()
{ {
Vehicle veh = PED::GET_VEHICLE_PED_IS_IN(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g.selected_player.id), false); Vehicle veh = PED::GET_VEHICLE_PED_IS_IN(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->m_selected_player->id()), false);
teleport::into_vehicle(veh); teleport::into_vehicle(veh);
}QUEUE_JOB_END_CLAUSE }QUEUE_JOB_END_CLAUSE

View File

@ -16,7 +16,11 @@ namespace big
{ {
QUEUE_JOB_BEGIN_CLAUSE() QUEUE_JOB_BEGIN_CLAUSE()
{ {
toxic::blame_explode_player(g.selected_player.id, g.selected_player.id, eExplosionType::PLANE, 1000, false, true, 0.f); toxic::blame_explode_player(
g_player_service->m_selected_player->id(),
g_player_service->m_selected_player->id(),
eExplosionType::PLANE, 1000, false, true, 0.f
);
}QUEUE_JOB_END_CLAUSE }QUEUE_JOB_END_CLAUSE
} }

View File

@ -4,18 +4,19 @@
namespace big namespace big
{ {
void window::player() void window::w_player()
{ {
if (!g.selected_player.is_online) if (g_player_service->m_selected_player == nullptr || !g_player_service->m_selected_player->is_valid())
{ {
g.window.player = false; g.window.player = false;
return; return;
} }
else g.window.player = true;
char title[64]; char title[64];
strcpy(title, "Player Options: "); strcpy(title, "Player Options: ");
strcat(title, g.selected_player.name); strcat(title, g_player_service->m_selected_player->get_name());
strcat(title, "###player_options"); strcat(title, "###player_options");
ImGui::SetNextWindowSize({ 350.f, 300.f }, ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize({ 350.f, 300.f }, ImGuiCond_FirstUseEver);
@ -29,5 +30,8 @@ namespace big
ImGui::End(); ImGui::End();
} }
if (!g.window.player)
g_player_service->m_selected_player = nullptr;
} }
} }

View File

@ -1,7 +1,6 @@
#include <algorithm>
#include <iterator>
#include "gui/window.hpp" #include "gui/window.hpp"
#include "imgui.h" #include "imgui.h"
#include "services/player_service.hpp"
namespace big namespace big
{ {
@ -14,74 +13,14 @@ namespace big
ImGui::SetNextWindowPos({ g.window.x - width, height_correction }, ImGuiCond_Always); ImGui::SetNextWindowPos({ g.window.x - width, height_correction }, ImGuiCond_Always);
if (g.window.users && ImGui::Begin("###player_menu", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav)) if (g.window.users && ImGui::Begin("###player_menu", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav))
{ {
auto vecButtonWidth = ImVec2(ImGui::GetWindowSize().x - 15.f, 0.0f); for (auto& item : g_player_service->m_players)
//ImGui::TextColored({ 255,255,255,255 }, "YOU:");
//if (ImGui::Button(g_player.name, vecButtonWidth))
//{
// g_selectedPlayer = g_player;
// g_temp.windows.player = true;
//}
//ImGui::Separator();
CPlayer players[32];
std::copy(std::begin(g.players), std::end(g.players), std::begin(players));
std::sort(std::begin(players), std::end(players));
char title[64];
sprintf(title, "Friends (%d)###friend_lists", g.friend_count);
if (ImGui::TreeNode(title))
{ {
ImGui::Unindent(); std::unique_ptr<player>& plyr = item.second;
if (ImGui::Button(plyr->get_name(), { ImGui::GetWindowSize().x - 15.f, 0.f }))
bool friendInLobby = false;
for (auto& player : players)
{ {
if (player.is_friend && player.is_online) g_player_service->m_selected_player = plyr.get();
{
friendInLobby = true;
if (ImGui::Button(player.name, vecButtonWidth))
{
g.selected_player = player;
g.window.player = true;
} }
} }
}
if (!friendInLobby)
{
ImGui::TextColored({ 180,180,180,255 }, "No friends in\ncurrent lobby.");
}
ImGui::Indent();
ImGui::TreePop();
ImGui::Separator();
}
sprintf(title, "Players (%d)###player_lists", g.player_count);
if (ImGui::TreeNode(title))
{
ImGui::Unindent();
for (auto& player : players)
{
if (!player.is_friend && player.is_online)
{
if (ImGui::Button(player.name, vecButtonWidth))
{
g.selected_player = player;
g.window.player = true;
}
}
}
ImGui::Indent();
ImGui::TreePop();
}
ImGui::End(); ImGui::End();
} }

View File

@ -34,6 +34,9 @@ namespace big
// GTA Thread Kill // GTA Thread Kill
m_gta_thread_kill_hook("GTK", g_pointers->m_gta_thread_kill, &hooks::gta_thread_kill), m_gta_thread_kill_hook("GTK", g_pointers->m_gta_thread_kill, &hooks::gta_thread_kill),
// Network Player Mgr Shutdown
m_network_player_mgr_shutdown_hook("NPMS", g_pointers->m_network_player_mgr_shutdown, &hooks::network_player_mgr_shutdown),
// Increment Stat Event // Increment Stat Event
m_increment_stat_hook("ISE", g_pointers->m_increment_stat_event, &hooks::increment_stat_event), m_increment_stat_hook("ISE", g_pointers->m_increment_stat_event, &hooks::increment_stat_event),
// Is DLC Present // Is DLC Present
@ -83,6 +86,8 @@ namespace big
m_gta_thread_kill_hook.enable(); m_gta_thread_kill_hook.enable();
m_gta_thread_tick_hook.enable(); m_gta_thread_tick_hook.enable();
m_network_player_mgr_shutdown_hook.enable();
m_player_has_joined_hook.enable(); m_player_has_joined_hook.enable();
m_player_has_left_hook.enable(); m_player_has_left_hook.enable();
@ -116,6 +121,8 @@ namespace big
m_player_has_joined_hook.disable(); m_player_has_joined_hook.disable();
m_player_has_left_hook.disable(); m_player_has_left_hook.disable();
m_network_player_mgr_shutdown_hook.disable();
m_gta_thread_tick_hook.disable(); m_gta_thread_tick_hook.disable();
m_gta_thread_kill_hook.disable(); m_gta_thread_kill_hook.disable();
m_gta_thread_start_hook.disable(); m_gta_thread_start_hook.disable();

View File

@ -40,6 +40,8 @@ namespace big
static rage::eThreadState gta_thread_tick(GtaThread* a1, unsigned int a2); static rage::eThreadState gta_thread_tick(GtaThread* a1, unsigned int a2);
static rage::eThreadState gta_thread_kill(GtaThread* thread); static rage::eThreadState gta_thread_kill(GtaThread* thread);
static void network_player_mgr_shutdown(CNetworkPlayerMgr* _this);
static void player_join(CNetworkObjectMgr* _this, CNetGamePlayer* net_player); static void player_join(CNetworkObjectMgr* _this, CNetGamePlayer* net_player);
static void player_leave(CNetworkObjectMgr* _this, CNetGamePlayer* net_player); static void player_leave(CNetworkObjectMgr* _this, CNetGamePlayer* net_player);
@ -95,6 +97,8 @@ namespace big
detour_hook m_gta_thread_tick_hook; detour_hook m_gta_thread_tick_hook;
detour_hook m_gta_thread_kill_hook; detour_hook m_gta_thread_kill_hook;
detour_hook m_network_player_mgr_shutdown_hook;
detour_hook m_player_has_joined_hook; detour_hook m_player_has_joined_hook;
detour_hook m_player_has_left_hook; detour_hook m_player_has_left_hook;

View File

@ -0,0 +1,12 @@
#include "hooking.hpp"
#include "services/player_service.hpp"
namespace big
{
void hooks::network_player_mgr_shutdown(CNetworkPlayerMgr* _this)
{
g_player_service->do_cleanup();
return g_hooking->m_network_player_mgr_shutdown_hook.get_original<decltype(&hooks::network_player_mgr_shutdown)>()(_this);
}
}

View File

@ -1,4 +1,5 @@
#include "hooking.hpp" #include "hooking.hpp"
#include "services/player_service.hpp"
namespace big namespace big
{ {
@ -6,6 +7,8 @@ namespace big
{ {
LOG(INFO) << "Player '" << net_player->get_name() << "' joined taking slot #" << (int)net_player->m_player_id; LOG(INFO) << "Player '" << net_player->get_name() << "' joined taking slot #" << (int)net_player->m_player_id;
g_player_service->player_join(net_player);
return g_hooking->m_player_has_joined_hook.get_original<decltype(&hooks::player_join)>()(_this, net_player); return g_hooking->m_player_has_joined_hook.get_original<decltype(&hooks::player_join)>()(_this, net_player);
} }
} }

View File

@ -1,4 +1,5 @@
#include "hooking.hpp" #include "hooking.hpp"
#include "services/player_service.hpp"
namespace big namespace big
{ {
@ -6,6 +7,8 @@ namespace big
{ {
LOG(INFO) << "Player '" << net_player->get_name() << "' left freeing slot #" << (int)net_player->m_player_id; LOG(INFO) << "Player '" << net_player->get_name() << "' left freeing slot #" << (int)net_player->m_player_id;
g_player_service->player_leave(net_player);
return g_hooking->m_player_has_left_hook.get_original<decltype(&hooks::player_leave)>()(_this, net_player); return g_hooking->m_player_has_left_hook.get_original<decltype(&hooks::player_leave)>()(_this, net_player);
} }
} }

View File

@ -11,6 +11,7 @@
#include "native_hooks/native_hooks.hpp" #include "native_hooks/native_hooks.hpp"
#include "services/globals_service.hpp" #include "services/globals_service.hpp"
#include "services/player_service.hpp"
#include "services/mobile_service.hpp" #include "services/mobile_service.hpp"
#include "services/vehicle_service.hpp" #include "services/vehicle_service.hpp"
@ -49,47 +50,49 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
auto thread_pool_instance = std::make_unique<thread_pool>(); auto thread_pool_instance = std::make_unique<thread_pool>();
LOG(INFO) << "Thread pool initialized."; LOG(INFO) << "Thread pool initialized.";
auto globals_service_instace = std::make_unique<globals_service>();
auto mobile_service_instance = std::make_unique<mobile_service>();
auto player_service_instance = std::make_unique<player_service>();
auto vehicle_service_instance = std::make_unique<vehicle_service>();
LOG(INFO) << "Registered service instances...";
g_script_mgr.add_script(std::make_unique<script>(&features::script_func)); g_script_mgr.add_script(std::make_unique<script>(&features::script_func));
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func)); g_script_mgr.add_script(std::make_unique<script>(&gui::script_func));
LOG(INFO) << "Scripts registered."; LOG(INFO) << "Scripts registered.";
g_hooking->enable();
LOG(INFO) << "Hooking enabled.";
auto globals_service_instace = std::make_unique<globals_service>();
auto mobile_service_instance = std::make_unique<mobile_service>();
auto vehicle_service_instance = std::make_unique<vehicle_service>();
LOG(INFO) << "Registered service instances...";
auto native_hooks_instance = std::make_unique<native_hooks>(); auto native_hooks_instance = std::make_unique<native_hooks>();
LOG(INFO) << "Dynamic native hooker initialized."; LOG(INFO) << "Dynamic native hooker initialized.";
g_hooking->enable();
LOG(INFO) << "Hooking enabled.";
while (g_running) while (g_running)
{ {
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
} }
native_hooks_instance.reset();
LOG(INFO) << "Dynamic native hooker uninitialized.";
vehicle_service_instance.reset();
mobile_service_instance.reset();
globals_service_instace.reset();
LOG(INFO) << "Serviceses uninitialized.";
// Make sure that all threads created don't have any blocking loops
// otherwise make sure that they have stopped executing
g_thread_pool->destroy();
LOG(INFO) << "Destroyed thread pool.";
g_hooking->disable(); g_hooking->disable();
LOG(INFO) << "Hooking disabled."; LOG(INFO) << "Hooking disabled.";
std::this_thread::sleep_for(1000ms); std::this_thread::sleep_for(1000ms);
native_hooks_instance.reset();
LOG(INFO) << "Dynamic native hooker uninitialized.";
g_script_mgr.remove_all_scripts(); g_script_mgr.remove_all_scripts();
LOG(INFO) << "Scripts unregistered."; LOG(INFO) << "Scripts unregistered.";
vehicle_service_instance.reset();
mobile_service_instance.reset();
player_service_instance.reset();
globals_service_instace.reset();
LOG(INFO) << "Services uninitialized.";
// Make sure that all threads created don't have any blocking loops
// otherwise make sure that they have stopped executing
g_thread_pool->destroy();
LOG(INFO) << "Destroyed thread pool.";
thread_pool_instance.reset(); thread_pool_instance.reset();
LOG(INFO) << "Thread pool uninitialized."; LOG(INFO) << "Thread pool uninitialized.";

View File

@ -234,6 +234,12 @@ namespace big
m_player_has_left = ptr.sub(0x26).as<PVOID>(); m_player_has_left = ptr.sub(0x26).as<PVOID>();
}); });
// Network Player Mgr Shutdown
main_batch.add("NPMS", "41 57 48 81 EC ? ? ? ? 8A 81 ? ? ? ? 48", [this](memory::handle ptr)
{
m_network_player_mgr_shutdown = ptr.sub(0x17).as<PVOID>();
});
main_batch.run(memory::module(nullptr)); main_batch.run(memory::module(nullptr));
m_hwnd = FindWindowW(L"grcWindow", nullptr); m_hwnd = FindWindowW(L"grcWindow", nullptr);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
#include "CNetworkPlayerMgr.hpp"
#include "gta/fwddec.hpp" #include "gta/fwddec.hpp"
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "gta/replay.hpp" #include "gta/replay.hpp"
@ -52,6 +53,8 @@ namespace big
PVOID m_gta_thread_tick{}; PVOID m_gta_thread_tick{};
PVOID m_gta_thread_kill{}; PVOID m_gta_thread_kill{};
PVOID m_network_player_mgr_shutdown;
PVOID m_player_has_joined{}; PVOID m_player_has_joined{};
PVOID m_player_has_left{}; PVOID m_player_has_left{};

View File

@ -0,0 +1,126 @@
#include "gta_util.hpp"
#include "player_service.hpp"
#include "util/notify.hpp"
namespace big
{
player::player(CNetGamePlayer* net_game_player)
: m_net_game_player(net_game_player)
{
}
CAutomobile* player::get_current_vehicle()
{
if (CPed* ped = this->get_ped(); ped != nullptr)
if (CAutomobile* vehicle = ped->m_vehicle; vehicle != nullptr)
return vehicle;
return nullptr;
}
const char* player::get_name()
{
return m_net_game_player->get_name();
}
rage::netPlayerData* player::get_net_data()
{
return m_net_game_player->get_net_data();
}
CNetGamePlayer* player::get_net_game_player()
{
return m_net_game_player;
}
CPed* player::get_ped()
{
if (CPlayerInfo* player_info = this->get_player_info(); player_info != nullptr)
if (CPed* ped = player_info->m_ped; ped != nullptr)
return ped;
return nullptr;
}
CPlayerInfo* player::get_player_info()
{
if (m_net_game_player != nullptr && m_net_game_player->m_player_info != nullptr)
return m_net_game_player->m_player_info;
return nullptr;
}
uint8_t player::id()
{
return m_net_game_player->m_player_id;
}
bool player::is_host()
{
return m_net_game_player->is_host();
}
bool player::is_valid()
{
return m_net_game_player == nullptr ? false : m_net_game_player->is_valid();
}
std::string player::to_lowercase_identifier()
{
std::string lower = this->get_name();
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
return lower;
}
player_service::player_service()
{
if (CNetworkPlayerMgr* network_player_mgr = gta_util::get_network_player_mgr())
{
for (size_t i = 0; i < network_player_mgr->m_player_limit; i++)
{
if (CNetGamePlayer* net_game_player = network_player_mgr->m_player_list[i]; net_game_player != nullptr)
{
std::unique_ptr<player> plyr = std::make_unique<player>(net_game_player);
m_players.emplace(
plyr->to_lowercase_identifier(),
std::move(plyr)
);
}
}
}
g_player_service = this;
}
player_service::~player_service()
{
g_player_service = nullptr;
}
void player_service::do_cleanup()
{
m_players.clear();
}
void player_service::player_join(CNetGamePlayer* net_game_player)
{
if (net_game_player == nullptr) return;
notify::player_joined(net_game_player);
std::unique_ptr<player> plyr = std::make_unique<player>(net_game_player);
m_players.emplace(
plyr->to_lowercase_identifier(),
std::move(plyr)
);
}
void player_service::player_leave(CNetGamePlayer* net_game_player)
{
if (net_game_player == nullptr) return;
std::unique_ptr<player> plyr = std::make_unique<player>(net_game_player);
m_players.erase(plyr->to_lowercase_identifier());
}
}

View File

@ -0,0 +1,54 @@
#pragma once
namespace big
{
class player_service;
class player final
{
friend player_service;
CNetGamePlayer* m_net_game_player = nullptr;
std::string m_identifier;
public:
player(CNetGamePlayer* net_game_player);
virtual ~player() = default;
CAutomobile* get_current_vehicle();
const char* get_name();
rage::netPlayerData* get_net_data();
CNetGamePlayer* get_net_game_player();
CPed* get_ped();
CPlayerInfo* get_player_info();
uint8_t id();
bool is_host();
bool is_valid();
protected:
std::string to_lowercase_identifier();
};
typedef std::map<std::string, std::unique_ptr<player>> player_list;
class player_service final
{
public:
player_list m_players;
player* m_selected_player = nullptr;
player_service();
virtual ~player_service();
void do_cleanup();
std::unique_ptr<player>& get_by_name(std::string name);
void player_join(CNetGamePlayer* net_game_player);
void player_leave(CNetGamePlayer* net_game_player);
};
inline player_service* g_player_service{};
}

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "CNetGamePlayer.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "script.hpp" #include "script.hpp"
@ -45,15 +46,10 @@ namespace big::notify
HUD::END_TEXT_COMMAND_DISPLAY_HELP(0, 0, 1, -1); HUD::END_TEXT_COMMAND_DISPLAY_HELP(0, 0, 1, -1);
} }
inline void player_joined(CPlayer player) inline void player_joined(CNetGamePlayer* net_game_player)
{ {
char msg[64]; above_map(
fmt::format("<C>{}</C> joined.", net_game_player->get_name()).c_str()
strcpy(msg, "<C>"); );
strcat(msg, player.name);
strcat(msg, "</C>");
strcat(msg, " joined.");
above_map(msg);
} }
} }