feat(Api): Implemented SCUI Api (#712)
* feat(Api): Async joining via rid joiner * feat(cmake): disable cpr tests Co-authored-by: Yimura <24669514+Yimura@users.noreply.github.com>
This commit is contained in:
parent
792d765ffa
commit
551c165367
@ -13,6 +13,7 @@ include(scripts/minhook.cmake)
|
|||||||
include(scripts/g3log.cmake)
|
include(scripts/g3log.cmake)
|
||||||
include(scripts/pugixml.cmake)
|
include(scripts/pugixml.cmake)
|
||||||
include(scripts/json.cmake)
|
include(scripts/json.cmake)
|
||||||
|
include(scripts/cpr.cmake)
|
||||||
|
|
||||||
message("\nFetching custom modules")
|
message("\nFetching custom modules")
|
||||||
include(scripts/imgui.cmake)
|
include(scripts/imgui.cmake)
|
||||||
@ -44,7 +45,7 @@ target_include_directories(YimMenu PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_precompile_headers(YimMenu PRIVATE "${SRC_DIR}/common.hpp")
|
target_precompile_headers(YimMenu PRIVATE "${SRC_DIR}/common.hpp")
|
||||||
target_link_libraries(YimMenu PRIVATE pugixml minhook g3log imgui)
|
target_link_libraries(YimMenu PRIVATE pugixml minhook g3log imgui cpr)
|
||||||
|
|
||||||
# Warnings as errors
|
# Warnings as errors
|
||||||
set_property(TARGET YimMenu PROPERTY COMPILE_WARNING_AS_ERROR ON)
|
set_property(TARGET YimMenu PROPERTY COMPILE_WARNING_AS_ERROR ON)
|
||||||
|
11
scripts/cpr.cmake
Normal file
11
scripts/cpr.cmake
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
set(BUILD_CPR_TESTS OFF CACHE INTERNAL "")
|
||||||
|
FetchContent_Declare(
|
||||||
|
cpr
|
||||||
|
GIT_REPOSITORY https://github.com/libcpr/cpr.git
|
||||||
|
GIT_TAG 1986262ba4e0cb052161e9e7919aef5ef08217f0
|
||||||
|
GIT_PROGRESS TRUE
|
||||||
|
)
|
||||||
|
message("cpr")
|
||||||
|
FetchContent_MakeAvailable(cpr)
|
@ -27,6 +27,7 @@
|
|||||||
#include "services/player_database/player_database_service.hpp"
|
#include "services/player_database/player_database_service.hpp"
|
||||||
#include "services/hotkey/hotkey_service.hpp"
|
#include "services/hotkey/hotkey_service.hpp"
|
||||||
#include "services/matchmaking/matchmaking_service.hpp"
|
#include "services/matchmaking/matchmaking_service.hpp"
|
||||||
|
#include "services/api/api_service.hpp"
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||||
{
|
{
|
||||||
@ -38,7 +39,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
|||||||
g_hmodule = hmod;
|
g_hmodule = hmod;
|
||||||
g_main_thread = CreateThread(nullptr, 0, [](PVOID) -> DWORD
|
g_main_thread = CreateThread(nullptr, 0, [](PVOID) -> DWORD
|
||||||
{
|
{
|
||||||
while (!FindWindow("grcWindow", "Grand Theft Auto V"))
|
while (!FindWindow("grcWindow", nullptr))
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
|
|
||||||
std::filesystem::path base_dir = std::getenv("appdata");
|
std::filesystem::path base_dir = std::getenv("appdata");
|
||||||
@ -95,6 +96,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
|||||||
auto player_database_service_instance = std::make_unique<player_database_service>();
|
auto player_database_service_instance = std::make_unique<player_database_service>();
|
||||||
auto hotkey_service_instance = std::make_unique<hotkey_service>();
|
auto hotkey_service_instance = std::make_unique<hotkey_service>();
|
||||||
auto matchmaking_service_instance = std::make_unique<matchmaking_service>();
|
auto matchmaking_service_instance = std::make_unique<matchmaking_service>();
|
||||||
|
auto api_service_instance = std::make_unique<api_service>();
|
||||||
LOG(INFO) << "Registered service instances...";
|
LOG(INFO) << "Registered service instances...";
|
||||||
|
|
||||||
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func, "GUI", false));
|
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func, "GUI", false));
|
||||||
@ -147,6 +149,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
|||||||
matchmaking_service_instance.reset();
|
matchmaking_service_instance.reset();
|
||||||
LOG(INFO) << "Matchmaking Service reset.";
|
LOG(INFO) << "Matchmaking Service reset.";
|
||||||
player_database_service_instance.reset();
|
player_database_service_instance.reset();
|
||||||
|
LOG(INFO) << "API Service reset.";
|
||||||
|
api_service_instance.reset();
|
||||||
LOG(INFO) << "Player Database Service reset.";
|
LOG(INFO) << "Player Database Service reset.";
|
||||||
script_patcher_service_instance.reset();
|
script_patcher_service_instance.reset();
|
||||||
LOG(INFO) << "Script Patcher Service reset.";
|
LOG(INFO) << "Script Patcher Service reset.";
|
||||||
|
@ -636,6 +636,12 @@ namespace big
|
|||||||
m_chat_data = ptr.add(3).rip().as<ChatData**>();
|
m_chat_data = ptr.add(3).rip().as<ChatData**>();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Social Club Info
|
||||||
|
main_batch.add("SCI", "48 8B D3 48 8D 4C 24 ? 48 69 D2", [this](memory::handle ptr)
|
||||||
|
{
|
||||||
|
m_sc_info = ptr.sub(4).rip().as<ScInfo*>();
|
||||||
|
});
|
||||||
|
|
||||||
// Create Script Handler
|
// Create Script Handler
|
||||||
main_batch.add("CSH", "48 8D 05 ? ? ? ? 4C 8D 0D ? ? ? ? 41 83 C8 FF 48 89 03 89 53 70 88 53 74 4C 89 4B 68 48 89 93", [this](memory::handle ptr)
|
main_batch.add("CSH", "48 8D 05 ? ? ? ? 4C 8D 0D ? ? ? ? 41 83 C8 FF 48 89 03 89 53 70 88 53 74 4C 89 4B 68 48 89 93", [this](memory::handle ptr)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "base/HashTable.hpp"
|
#include "base/HashTable.hpp"
|
||||||
|
#include "socialclub/ScInfo.hpp"
|
||||||
#include "function_types.hpp"
|
#include "function_types.hpp"
|
||||||
#include "gta/fwddec.hpp"
|
#include "gta/fwddec.hpp"
|
||||||
#include "gta/replay.hpp"
|
#include "gta/replay.hpp"
|
||||||
@ -68,6 +69,7 @@ namespace big
|
|||||||
functions::write_player_game_state_data_node m_write_player_game_state_data_node{};
|
functions::write_player_game_state_data_node m_write_player_game_state_data_node{};
|
||||||
|
|
||||||
ChatData** m_chat_data;
|
ChatData** m_chat_data;
|
||||||
|
ScInfo* m_sc_info;
|
||||||
FriendRegistry* m_friend_registry{};
|
FriendRegistry* m_friend_registry{};
|
||||||
|
|
||||||
functions::get_screen_coords_for_world_coords m_get_screen_coords_for_world_coords{};
|
functions::get_screen_coords_for_world_coords m_get_screen_coords_for_world_coords{};
|
||||||
|
63
src/services/api/api_service.cpp
Normal file
63
src/services/api/api_service.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "api_service.hpp"
|
||||||
|
#include "pointers.hpp"
|
||||||
|
|
||||||
|
namespace big
|
||||||
|
{
|
||||||
|
|
||||||
|
api_service::api_service()
|
||||||
|
{
|
||||||
|
g_api_service = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_service::~api_service()
|
||||||
|
{
|
||||||
|
g_api_service = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool api_service::get_rid_from_username(std::string_view username, uint64_t& result)
|
||||||
|
{
|
||||||
|
cpr::Response response = cpr::Post(
|
||||||
|
cpr::Url{ "https://scui.rockstargames.com/api/friend/accountsearch" },
|
||||||
|
cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}},
|
||||||
|
cpr::Body{ { std::format("searchNickname={}", username) } });
|
||||||
|
|
||||||
|
if (response.status_code == 200)
|
||||||
|
{
|
||||||
|
nlohmann::json obj = nlohmann::json::parse(response.text);
|
||||||
|
if (obj["Total"] > 0 && username.compare(obj["Accounts"].at(0)["Nickname"]) == 0)
|
||||||
|
{
|
||||||
|
result = obj["Accounts"].at(0)["RockstarId"];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool api_service::get_username_from_rid(uint64_t rid, std::string& result)
|
||||||
|
{
|
||||||
|
cpr::Response response = cpr::Post(
|
||||||
|
cpr::Url{ "https://scui.rockstargames.com/api/friend/getprofile" },
|
||||||
|
cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} },
|
||||||
|
cpr::Body{ { std::format(R"({{"RockstarId":"{}"}})", rid) } });
|
||||||
|
|
||||||
|
if (response.status_code == 200)
|
||||||
|
{
|
||||||
|
nlohmann::json obj = nlohmann::json::parse(response.text);
|
||||||
|
result = obj["Accounts"].at(0)["RockstarAccount"]["Name"];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool api_service::send_socialclub_message(uint64_t rid, std::string_view message)
|
||||||
|
{
|
||||||
|
cpr::Response response = cpr::Post(
|
||||||
|
cpr::Url{ "https://scui.rockstargames.com/api/messaging/sendmessage" },
|
||||||
|
cpr::Header{ {"Authorization", AUTHORIZATION_TICKET) }, { "X-Requested-With", "XMLHttpRequest"}, {"Content-Type", "application/json"} },
|
||||||
|
cpr::Body{ { std::format(R"({{"env":"prod","title":"gta5","version":11,"recipientRockstarId":"{}","messageText":"{}"}})", rid, message) } });
|
||||||
|
|
||||||
|
return response.status_code == 200;
|
||||||
|
}
|
||||||
|
}
|
30
src/services/api/api_service.hpp
Normal file
30
src/services/api/api_service.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "pointers.hpp"
|
||||||
|
#include <cpr/cpr.h>
|
||||||
|
#define AUTHORIZATION_TICKET std::format("SCAUTH val=\"{}\"", get_ticket()
|
||||||
|
|
||||||
|
namespace big
|
||||||
|
{
|
||||||
|
class api_service
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
api_service();
|
||||||
|
~api_service();
|
||||||
|
|
||||||
|
// Returns true if an valid profile matching his username has been found
|
||||||
|
bool get_rid_from_username(std::string_view username, uint64_t& result);
|
||||||
|
|
||||||
|
// Returns true if an valid profile matching his rid has been found
|
||||||
|
bool get_username_from_rid(uint64_t rid, std::string& result);
|
||||||
|
|
||||||
|
// Returns true if the message has been successfully sended to the target
|
||||||
|
bool send_socialclub_message(uint64_t rid, std::string_view message);
|
||||||
|
private:
|
||||||
|
inline std::string get_ticket()
|
||||||
|
{
|
||||||
|
return g_pointers->m_sc_info->m_ticket;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline api_service* g_api_service;
|
||||||
|
}
|
@ -10,6 +10,9 @@
|
|||||||
#include "pointers.hpp"
|
#include "pointers.hpp"
|
||||||
#include "services/players/player_service.hpp"
|
#include "services/players/player_service.hpp"
|
||||||
#include "services/player_database/player_database_service.hpp"
|
#include "services/player_database/player_database_service.hpp"
|
||||||
|
#include "services/api/api_service.hpp"
|
||||||
|
#include "thread_pool.hpp"
|
||||||
|
#include "fiber_pool.hpp"
|
||||||
|
|
||||||
namespace big::session
|
namespace big::session
|
||||||
{
|
{
|
||||||
@ -101,6 +104,23 @@ namespace big::session
|
|||||||
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void join_by_username(std::string username)
|
||||||
|
{
|
||||||
|
g_thread_pool->push([username]
|
||||||
|
{
|
||||||
|
uint64_t rid;
|
||||||
|
if (g_api_service->get_rid_from_username(username, rid))
|
||||||
|
{
|
||||||
|
g_fiber_pool->queue_job([rid]
|
||||||
|
{
|
||||||
|
join_by_rockstar_id(rid);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
inline void add_infraction(player_ptr player, Infraction infraction)
|
inline void add_infraction(player_ptr player, Infraction infraction)
|
||||||
{
|
{
|
||||||
auto plyr = g_player_database_service->get_or_create_player(player);
|
auto plyr = g_player_database_service->get_or_create_player(player);
|
||||||
|
@ -16,11 +16,18 @@ namespace big
|
|||||||
{
|
{
|
||||||
static uint64_t rid = 0;
|
static uint64_t rid = 0;
|
||||||
ImGui::InputScalar("Input RID", ImGuiDataType_U64, &rid);
|
ImGui::InputScalar("Input RID", ImGuiDataType_U64, &rid);
|
||||||
components::button("Join RID", []
|
components::button("Join by RID", []
|
||||||
{
|
{
|
||||||
session::join_by_rockstar_id(rid);
|
session::join_by_rockstar_id(rid);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static char username[20];
|
||||||
|
ImGui::InputText("Input Username", username, sizeof(username));
|
||||||
|
if (components::button("Join by Username"))
|
||||||
|
{
|
||||||
|
session::join_by_username(username);
|
||||||
|
};
|
||||||
|
|
||||||
static char base64[500]{};
|
static char base64[500]{};
|
||||||
ImGui::InputText("Session Info", base64, sizeof(base64));
|
ImGui::InputText("Session Info", base64, sizeof(base64));
|
||||||
components::button("Join Session Info", []
|
components::button("Join Session Info", []
|
||||||
|
Reference in New Issue
Block a user