Network Time (#724)

* fix(NativeHooks): Fix softlock when loading Cayo Perico
* fear(netTime): Try to modify time remotely
* fix(timeSync): Make it work more consistently
* feat(netTime): net time sync for all!
This commit is contained in:
maybegreat48 2022-12-19 17:39:06 +00:00 committed by GitHub
parent e442e284db
commit c2e9e61c01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 189 additions and 4 deletions

View File

@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
gtav_classes gtav_classes
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
GIT_TAG fa5e1d119c025f739075920447eedb7942f5e1fa GIT_TAG 5ab30af647d7e64404d76ea6168e7f78f5e365af
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""

View File

@ -11,6 +11,7 @@ namespace big
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 00 07 00 00 5D ? ? ? 56 ? ? 71", 5, { 0x2E, 0x00, 0x00 }, &g.tunables.no_idle_kick }); g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 00 07 00 00 5D ? ? ? 56 ? ? 71", 5, { 0x2E, 0x00, 0x00 }, &g.tunables.no_idle_kick });
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "5D ? ? ? 76 57 ? ? 5D ? ? ? 76", 0, { 0x2E, 0x00, 0x00 }, nullptr }); // end session kick protection g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "5D ? ? ? 76 57 ? ? 5D ? ? ? 76", 0, { 0x2E, 0x00, 0x00 }, nullptr }); // end session kick protection
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "71 2E ? ? 55 ? ? 61 ? ? ? 47 ? ? 63", 0, { 0x72 }, nullptr }); // load island even if stranded animal IPL choice is not set
g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, { 0x71, 0x2E, 0x01, 0x01 }, nullptr }); // despawn bypass g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, { 0x71, 0x2E, 0x01, 0x01 }, nullptr }); // despawn bypass
g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "38 00 5D ? ? ? 38 00 5D ? ? ? 38 00 41", 0, std::vector<uint8_t>(12, 0x0), nullptr}); // godmode/invisibility detection bypass g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "38 00 5D ? ? ? 38 00 5D ? ? ? 38 00 41", 0, std::vector<uint8_t>(12, 0x0), nullptr}); // godmode/invisibility detection bypass

View File

@ -14,6 +14,7 @@ namespace rage
class snSession; class snSession;
class snPlayer; class snPlayer;
class CDynamicEntity; class CDynamicEntity;
class netTimeSyncMsg;
} }
namespace datafile_commands namespace datafile_commands
@ -115,4 +116,6 @@ namespace big::functions
using load_cloud_file = void(*)(sCloudFile** out_cloud_file, char* buffer, int size, const char* reason); using load_cloud_file = void(*)(sCloudFile** out_cloud_file, char* buffer, int size, const char* reason);
using set_as_active_cloud_file = void(*)(datafile_commands::SveFileObject* object, sCloudFile** file); using set_as_active_cloud_file = void(*)(datafile_commands::SveFileObject* object, sCloudFile** file);
using save_json_data = char*(*)(datafile_commands::SveFileObject* object, int* out_length, const char* reason); using save_json_data = char*(*)(datafile_commands::SveFileObject* object, int* out_length, const char* reason);
using sync_network_time = bool(*)(rage::netConnectionManager* mgr, rage::netConnectionPeer* peer, int connection_id, rage::netTimeSyncMsg* msg, int flags);
} }

View File

@ -397,7 +397,8 @@ namespace rage
virtual EventType get_event_type() = 0; virtual EventType get_event_type() = 0;
virtual uint32_t _0x18() = 0; virtual uint32_t _0x18() = 0;
char pad_0008[56]; //0x0008 uint32_t m_timestamp; //0x0008
char pad_0008[52]; //0x000C
uint32_t m_msg_id; //0x0040 uint32_t m_msg_id; //0x0040
uint32_t m_connection_identifier; //0x0044 uint32_t m_connection_identifier; //0x0044
InFrame* m_this; //0x0048 InFrame* m_this; //0x0048

View File

@ -6,6 +6,7 @@
#include "util/spam.hpp" #include "util/spam.hpp"
#include "util/kick.hpp" #include "util/kick.hpp"
#include <network/Network.hpp> #include <network/Network.hpp>
#include <network/netTime.hpp>
namespace big namespace big
{ {
@ -218,6 +219,26 @@ namespace big
break; break;
} }
case rage::eNetMessage::MsgNetTimeSync:
{
if (player)
{
int action = buffer.Read<int>(2);
uint32_t counter = buffer.Read<uint32_t>(32);
uint32_t token = buffer.Read<uint32_t>(32);
uint32_t timestamp = buffer.Read<uint32_t>(32);
uint32_t time_diff = (*g_pointers->m_network_time)->m_time_offset + frame->m_timestamp;
if (action == 0)
{
player->player_time_value = timestamp;
player->player_time_value_received_time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
if (!player->time_difference || time_diff > player->time_difference.value())
player->time_difference = time_diff;
}
}
break;
}
} }
} }
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "script_function.hpp"
namespace big namespace big
{ {
@ -54,7 +55,7 @@ namespace big
}); });
} }
*scr_globals::gsbd.as<int*>() = 4; scr_functions::set_freemode_session_active({});
src->set_return_value<BOOL>(TRUE); src->set_return_value<BOOL>(TRUE);
} }
} }

View File

@ -732,6 +732,18 @@ namespace big
m_save_json_data = ptr.as<functions::save_json_data>(); m_save_json_data = ptr.as<functions::save_json_data>();
}); });
// Network Time
main_batch.add("NT", "48 8B 0D ? ? ? ? E8 ? ? ? ? 33 DB 84 C0 74 41", [this](memory::handle ptr)
{
m_network_time = ptr.add(3).rip().as<rage::netTime**>();
});
// Sync Network Time
main_batch.add("SNT", "E8 ? ? ? ? 8B 43 5C", [this](memory::handle ptr)
{
m_sync_network_time = ptr.add(1).rip().as<functions::sync_network_time>();
});
// Queue Dependency // Queue Dependency
main_batch.add("QD", "48 89 5C 24 ? 57 48 83 EC ? 0F B6 99", [this](memory::handle ptr) main_batch.add("QD", "48 89 5C 24 ? 57 48 83 EC ? 0F B6 99", [this](memory::handle ptr)
{ {

View File

@ -18,6 +18,7 @@ namespace rage
template<typename T> template<typename T>
class atSingleton; class atSingleton;
class RageSecurity; class RageSecurity;
class netTime;
} }
namespace big namespace big
@ -217,6 +218,9 @@ namespace big
functions::load_cloud_file m_load_cloud_file; functions::load_cloud_file m_load_cloud_file;
functions::set_as_active_cloud_file m_set_as_active_cloud_file; functions::set_as_active_cloud_file m_set_as_active_cloud_file;
functions::save_json_data m_save_json_data; functions::save_json_data m_save_json_data;
rage::netTime** m_network_time;
functions::sync_network_time m_sync_network_time;
}; };
inline pointers* g_pointers{}; inline pointers* g_pointers{};

View File

@ -27,6 +27,7 @@ namespace big
namespace scr_functions namespace scr_functions
{ {
static inline script_function join_ceo("JC", RAGE_JOAAT("freemode"), "2D 04 1D 00 00 5D", 0); static inline script_function join_ceo("JC", RAGE_JOAAT("freemode"), "2D 04 1D 00 00 5D", 0);
static inline script_function set_freemode_session_active("SFSA", RAGE_JOAAT("freemode"), "2D 00 02 00 00 75 5D ? ? ? 50", 0);
static inline script_function dance_loop("DL", RAGE_JOAAT("am_mp_nightclub"), "2D 00 14 00 00 4F ? ? 47 ? ? 5D ? ? ? 56", 0); static inline script_function dance_loop("DL", RAGE_JOAAT("am_mp_nightclub"), "2D 00 14 00 00 4F ? ? 47 ? ? 5D ? ? ? 56", 0);
static inline script_function init_nightclub_script("INS", RAGE_JOAAT("am_mp_nightclub"), "2D 00 11 00 00 4F", 0); static inline script_function init_nightclub_script("INS", RAGE_JOAAT("am_mp_nightclub"), "2D 00 11 00 00 4F", 0);

View File

@ -60,6 +60,11 @@ namespace big
int block_join_reason = 0; int block_join_reason = 0;
bool is_spammer = false; bool is_spammer = false;
std::optional<std::uint32_t> player_time_value;
std::optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>> player_time_value_received_time;
std::optional<std::uint32_t> time_difference;
std::uint32_t num_time_syncs_sent = 9999;
protected: protected:
bool equals(const CNetGamePlayer* net_game_player) const; bool equals(const CNetGamePlayer* net_game_player) const;

View File

@ -22,7 +22,9 @@ namespace
".gg", ".gg",
"--->", "--->",
"shopgta5", "shopgta5",
"doit#" "doit#",
"krutka#",
"<b>"
}; };
} }

View File

@ -8,6 +8,11 @@
#include "util/scripts.hpp" #include "util/scripts.hpp"
#include "services/gta_data/gta_data_service.hpp" #include "services/gta_data/gta_data_service.hpp"
#include "util/system.hpp" #include "util/system.hpp"
#include <network/Network.hpp>
#include <network/netTime.hpp>
#include <timeapi.h>
#pragma comment(lib, "winmm.lib")
namespace big::toxic namespace big::toxic
{ {
@ -344,4 +349,101 @@ namespace big::toxic
{ {
WEAPON::REMOVE_ALL_PED_WEAPONS(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(target->id()), FALSE); WEAPON::REMOVE_ALL_PED_WEAPONS(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(target->id()), FALSE);
} }
inline bool set_time(player_ptr target, uint32_t millis)
{
if (!g_player_service->get_self()->is_host())
{
g_notification_service->push_error("Modify Time", "Modifying time requires session host");
return false;
}
if (!target->player_time_value.has_value())
{
g_notification_service->push_error("Modify Time", "We do not have the player's timestamp yet");
return false;
}
target->num_time_syncs_sent++;
rage::netTimeSyncMsg msg{};
msg.action = 1;
msg.counter = target->num_time_syncs_sent;
msg.token = (*g_pointers->m_network_time)->m_time_token;
msg.timestamp = target->player_time_value.value() + (uint32_t)(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()) - target->player_time_value_received_time.value()).count();
msg.increment = millis;
auto peer = g_pointers->m_get_connection_peer(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr, (int)target->get_session_player()->m_player_data.m_peer_id_2);
for (int j = 0; j < 100; j++)
{
g_pointers->m_sync_network_time(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr,
peer, (*g_pointers->m_network_time)->m_connection_identifier, &msg, 0x1000000); // repeatedly spamming the event will eventually cause certain bounds checks to disable for some reason
}
return true;
}
inline void warp_time_forward(player_ptr target, uint32_t millis)
{
if (!target->player_time_value.has_value())
{
g_notification_service->push_error("Warp Time", "We do not have the player's timestamp yet");
return;
}
if (set_time(target, target->time_difference.value() + millis + (uint32_t)(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()) - target->player_time_value_received_time.value()).count()))
target->time_difference.value() += millis;
}
inline void set_time_all(uint32_t millis)
{
if (!g_player_service->get_self()->is_host())
{
g_notification_service->push_error("Modify Time", "Modifying time requires session host");
return;
}
std::uint32_t largest_counter = 9999;
g_player_service->iterate([&largest_counter](const player_entry& plyr)
{
if (plyr.second->num_time_syncs_sent > largest_counter)
largest_counter = plyr.second->num_time_syncs_sent;
});
(*g_pointers->m_network_time)->m_time_offset = millis - timeGetTime();
rage::netTimeSyncMsg msg{};
g_player_service->iterate([&largest_counter, &msg, millis](const player_entry& plyr)
{
if (!plyr.second->player_time_value.has_value())
{
LOG(WARNING) << "Skipping " << plyr.second->get_name() << " in time warp";
return;
}
largest_counter++;
msg.action = 1;
msg.counter = largest_counter;
msg.token = (*g_pointers->m_network_time)->m_time_token;
msg.timestamp = plyr.second->player_time_value.value() + (uint32_t)(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()) - plyr.second->player_time_value_received_time.value()).count();
msg.increment = millis;
auto peer = g_pointers->m_get_connection_peer(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr, (int)plyr.second->get_session_player()->m_player_data.m_peer_id_2);
for (int j = 0; j < 25; j++)
{
g_pointers->m_sync_network_time(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr,
peer, (*g_pointers->m_network_time)->m_connection_identifier, &msg, 0x1000000);
}
plyr.second->num_time_syncs_sent = largest_counter + 32;
});
}
inline void warp_time_forward_all(uint32_t millis)
{
set_time_all((*g_pointers->m_network_time)->m_time + millis);
}
} }

View File

@ -319,6 +319,22 @@ namespace big
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("Force Thunder", &g.session.force_thunder); ImGui::Checkbox("Force Thunder", &g.session.force_thunder);
components::small_text("Warp Time (requires session host)");
components::button("+1 Minute", [] { toxic::warp_time_forward_all(60 * 1000); });
ImGui::SameLine();
components::button("+5 Minutes", [] { toxic::warp_time_forward_all(5 * 60 * 1000); });
ImGui::SameLine();
components::button("+48 Minutes", [] { toxic::warp_time_forward_all(48 * 60 * 1000); });
ImGui::SameLine();
components::button("+96 Minutes", [] { toxic::warp_time_forward_all(96 * 60 * 1000); });
ImGui::SameLine();
components::button("+200 Minutes", [] { toxic::warp_time_forward_all(200 * 60 * 1000); });
ImGui::SameLine();
components::button("Stop Time", [] { toxic::set_time_all(INT_MAX - 3000); });
if (ImGui::IsItemHovered())
ImGui::SetTooltip("This cannot be reversed. Use with caution");
components::sub_title("Script Host Features"); components::sub_title("Script Host Features");
ImGui::Checkbox("Disable CEO Money", &g.session.block_ceo_money); ImGui::Checkbox("Disable CEO Money", &g.session.block_ceo_money);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())

View File

@ -109,6 +109,22 @@ namespace big
ImGui::SameLine(); ImGui::SameLine();
components::button("Remove All Weapons", [] { toxic::remove_all_weapons(g_player_service->get_selected()); }); components::button("Remove All Weapons", [] { toxic::remove_all_weapons(g_player_service->get_selected()); });
components::small_text("Warp Time (requires session host)");
components::button("+1 Minute", [] { toxic::warp_time_forward(g_player_service->get_selected(), 60 * 1000); });
ImGui::SameLine();
components::button("+5 Minutes", [] { toxic::warp_time_forward(g_player_service->get_selected(), 5 * 60 * 1000); });
ImGui::SameLine();
components::button("+48 Minutes", [] { toxic::warp_time_forward(g_player_service->get_selected(), 48 * 60 * 1000); });
ImGui::SameLine();
components::button("+96 Minutes", [] { toxic::warp_time_forward(g_player_service->get_selected(), 96 * 60 * 1000); });
ImGui::SameLine();
components::button("+200 Minutes", [] { toxic::warp_time_forward(g_player_service->get_selected(), 200 * 60 * 1000); });
ImGui::SameLine();
components::button("Stop Time", [] { toxic::set_time(g_player_service->get_selected(), INT_MAX - 3000); });
if (ImGui::IsItemHovered())
ImGui::SetTooltip("This cannot be reversed. Use with caution");
ImGui::TreePop(); ImGui::TreePop();
} }
} }