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:
Bugisoft 2022-12-17 17:24:45 +01:00 committed by GitHub
parent 792d765ffa
commit 551c165367
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 148 additions and 4 deletions

View File

@ -13,6 +13,7 @@ include(scripts/minhook.cmake)
include(scripts/g3log.cmake)
include(scripts/pugixml.cmake)
include(scripts/json.cmake)
include(scripts/cpr.cmake)
message("\nFetching custom modules")
include(scripts/imgui.cmake)
@ -44,7 +45,7 @@ target_include_directories(YimMenu PRIVATE
)
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
set_property(TARGET YimMenu PROPERTY COMPILE_WARNING_AS_ERROR ON)

11
scripts/cpr.cmake Normal file
View 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)

View File

@ -27,6 +27,7 @@
#include "services/player_database/player_database_service.hpp"
#include "services/hotkey/hotkey_service.hpp"
#include "services/matchmaking/matchmaking_service.hpp"
#include "services/api/api_service.hpp"
BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
{
@ -38,7 +39,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
g_hmodule = hmod;
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::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 hotkey_service_instance = std::make_unique<hotkey_service>();
auto matchmaking_service_instance = std::make_unique<matchmaking_service>();
auto api_service_instance = std::make_unique<api_service>();
LOG(INFO) << "Registered service instances...";
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();
LOG(INFO) << "Matchmaking Service reset.";
player_database_service_instance.reset();
LOG(INFO) << "API Service reset.";
api_service_instance.reset();
LOG(INFO) << "Player Database Service reset.";
script_patcher_service_instance.reset();
LOG(INFO) << "Script Patcher Service reset.";

View File

@ -636,6 +636,12 @@ namespace big
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
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)
{

View File

@ -1,6 +1,7 @@
#pragma once
#include "common.hpp"
#include "base/HashTable.hpp"
#include "socialclub/ScInfo.hpp"
#include "function_types.hpp"
#include "gta/fwddec.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{};
ChatData** m_chat_data;
ScInfo* m_sc_info;
FriendRegistry* m_friend_registry{};
functions::get_screen_coords_for_world_coords m_get_screen_coords_for_world_coords{};

View 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;
}
}

View 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;
}

View File

@ -10,6 +10,9 @@
#include "pointers.hpp"
#include "services/players/player_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
{
@ -101,6 +104,23 @@ namespace big::session
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)
{
auto plyr = g_player_database_service->get_or_create_player(player);

View File

@ -16,11 +16,18 @@ namespace big
{
static uint64_t rid = 0;
ImGui::InputScalar("Input RID", ImGuiDataType_U64, &rid);
components::button("Join RID", []
components::button("Join by 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]{};
ImGui::InputText("Session Info", base64, sizeof(base64));
components::button("Join Session Info", []