From 6e0df48ce2c451cb907ae40a1352db5926fc316e Mon Sep 17 00:00:00 2001 From: maybegreat48 <96936658+maybegreat48@users.noreply.github.com> Date: Sat, 29 Mar 2025 00:33:35 -0400 Subject: [PATCH] feat: try to implement a kick --- CONTRIBUTING.md | 6 + README.md | 24 +++- .../features/players/kick/ScriptHostKick.cpp | 22 ++++ src/game/features/system/LSCCustomsBypass.cpp | 4 +- src/game/frontend/submenus/Player/Kick.cpp | 16 +++ src/game/frontend/submenus/Player/Kick.hpp | 8 ++ src/game/frontend/submenus/Players.cpp | 2 + src/game/gta/Scripts.cpp | 25 +++++ src/game/gta/Scripts.hpp | 1 + .../script/CGameScriptHandlerNetComponent.hpp | 105 ++++++++++++++++++ .../script/scriptHandlerNetComponent.hpp | 15 +++ 11 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 src/game/features/players/kick/ScriptHostKick.cpp create mode 100644 src/game/frontend/submenus/Player/Kick.cpp create mode 100644 src/game/frontend/submenus/Player/Kick.hpp create mode 100644 src/types/script/CGameScriptHandlerNetComponent.hpp create mode 100644 src/types/script/scriptHandlerNetComponent.hpp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0e62d2f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# YimMenu Contribution Guide (WIP) + +## Structure + +- `core/` : Essential general features for the base +- `game/` : Game specific implemented things \ No newline at end of file diff --git a/README.md b/README.md index 013ad15..a4e9dcd 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,24 @@ Experimental menu for GTA 5: Enhanced -## Structure +## How to use -- `core/` : Essential general features for the base -- `game/` : Game specific implemented things -- `util/` : Loose functions that aren't game specific \ No newline at end of file +1. Download the latest version of FSL from [here](https://www.unknowncheats.me/forum/grand-theft-auto-v/616977-fsl-local-gtao-saves.html) and place version.dll in your GTA V directory. Using FSL is now optional but highly recommended for account safety +2. Download YimMenuV2 from [GitHub Releases](https://github.com/YimMenu/YimMenuV2/releases/tag/nightly) +3. Download an injector, such as [Xenos](https://www.unknowncheats.me/forum/general-programming-and-reversing/124013-xenos-injector-v2-3-2-a.html) +4. Open Rockstar Launcher, select Grand Theft Auto V Enhanced, go to settings, and disable BattlEye. If you are using Steam or Epic Games, you may have to pass the -nobattleye command line parameter as well +5. Launch GTA V, then use your injector to inject YimMenuV2.dll at the main menu + +## Common issues + +### I keep getting desynced from public sessions every five minutes + +We currently do not have a BattlEye bypass, and legitimate hosts will eventually remove you due to a heartbeat failure. There is currently no way to stop this other than using an actual (private) bypass + +### I removed FSL and all my progress disappeared! + +FSL reroutes account save data to disk, so any progress made with FSL will only show up if you have FSL enabled. If you don't want this, you can also use YimMenuV2 without FSL, but this is not recommended + +### I removed FSL and the game doesn't start up anymore + +This is a known issue; delete "Documents/GTAV Enhanced/Profiles" to fix \ No newline at end of file diff --git a/src/game/features/players/kick/ScriptHostKick.cpp b/src/game/features/players/kick/ScriptHostKick.cpp new file mode 100644 index 0000000..b602e91 --- /dev/null +++ b/src/game/features/players/kick/ScriptHostKick.cpp @@ -0,0 +1,22 @@ +#include "game/commands/PlayerCommand.hpp" +#include "types/script/globals/GSBD_Kicking.hpp" +#include "game/gta/Scripts.hpp" + +namespace YimMenu::Features +{ + class ScriptHostKick : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + + virtual void OnCall(Player player) override + { + if (auto freemode = Scripts::FindScriptThread("freemode"_J); freemode && Scripts::SafeToModifyFreemodeBroadcastGlobals()) + { + Scripts::ForceScriptHost(freemode); + GSBD_Kicking::Get()->KickedPlayers[player.GetId()] = true; + } + } + }; + + static ScriptHostKick _ScriptHostKick{"shkick", "Script Host Kick", "Kicks the player by faking a vote kick"}; +} \ No newline at end of file diff --git a/src/game/features/system/LSCCustomsBypass.cpp b/src/game/features/system/LSCCustomsBypass.cpp index ffac782..b3615ad 100644 --- a/src/game/features/system/LSCCustomsBypass.cpp +++ b/src/game/features/system/LSCCustomsBypass.cpp @@ -3,7 +3,7 @@ namespace YimMenu::Features { -//from https://github.com/TCRoid/YimMenu-Lua-RS-Missions/ + // from https://github.com/TCRoid/YimMenu-Lua-RS-Missions/ class LSCCustomsBypass : public BoolCommand { using BoolCommand::BoolCommand; @@ -40,5 +40,5 @@ namespace YimMenu::Features } }; - static LSCCustomsBypass _LSCCustomsBypass{"lsccustomsbypass", "Remove LSC Restrictions", "Removes Los Santos Customs vehicle modification restrictions", false}; + static LSCCustomsBypass _LSCCustomsBypass{"lsccustomsbypass", "Remove LSC Restrictions", "Removes Los Santos Customs vehicle modification restrictions"}; } \ No newline at end of file diff --git a/src/game/frontend/submenus/Player/Kick.cpp b/src/game/frontend/submenus/Player/Kick.cpp new file mode 100644 index 0000000..32d49d0 --- /dev/null +++ b/src/game/frontend/submenus/Player/Kick.cpp @@ -0,0 +1,16 @@ +#include "Toxic.hpp" + +namespace YimMenu::Submenus +{ + std::shared_ptr BuildKickMenu() + { + auto menu = std::make_shared("Kick"); + + auto kicks = std::make_shared("Kicks"); + kicks->AddItem(std::make_shared("shkick"_J)); + + menu->AddItem(kicks); + + return menu; + } +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Player/Kick.hpp b/src/game/frontend/submenus/Player/Kick.hpp new file mode 100644 index 0000000..4075b6f --- /dev/null +++ b/src/game/frontend/submenus/Player/Kick.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "core/frontend/manager/Category.hpp" +#include "game/frontend/items/Items.hpp" + +namespace YimMenu::Submenus +{ + std::shared_ptr BuildKickMenu(); +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Players.cpp b/src/game/frontend/submenus/Players.cpp index 5fa742c..9c79776 100644 --- a/src/game/frontend/submenus/Players.cpp +++ b/src/game/frontend/submenus/Players.cpp @@ -3,6 +3,7 @@ #include "Player/Info.hpp" #include "Player/Toxic.hpp" #include "Player/Troll.hpp" +#include "Player/Kick.hpp" #include "core/frontend/widgets/imgui_colors.h" #include "game/backend/PlayerData.hpp" #include "game/backend/Players.hpp" @@ -118,6 +119,7 @@ namespace YimMenu::Submenus AddCategory(std::move(BuildInfoMenu())); AddCategory(std::move(BuildTrollMenu())); AddCategory(std::move(BuildToxicMenu())); + AddCategory(std::move(BuildKickMenu())); for (auto& category : m_Categories) category->PrependItem(std::make_shared([] { diff --git a/src/game/gta/Scripts.cpp b/src/game/gta/Scripts.cpp index e647b1f..ad1e52b 100644 --- a/src/game/gta/Scripts.cpp +++ b/src/game/gta/Scripts.cpp @@ -4,8 +4,11 @@ #include "types/rage/tlsContext.hpp" #include "types/script/GtaThread.hpp" #include "types/script/CGameScriptHandler.hpp" +#include "types/script/CGameScriptHandlerNetComponent.hpp" #include "types/script/CGameScriptId.hpp" #include "types/script/globals/GlobalPlayerBD.hpp" +#include "game/gta/Packet.hpp" +#include "game/backend/Players.hpp" #include "game/backend/Self.hpp" namespace YimMenu::Scripts @@ -77,4 +80,26 @@ namespace YimMenu::Scripts return false; } + + void ForceScriptHost(rage::scrThread* thread) + { + if (auto net_component = reinterpret_cast(thread)->m_NetComponent) + { + if (net_component->IsLocalPlayerHost()) + return; + + net_component->DoHostMigration(Self::GetPlayer().GetHandle(), net_component->m_HostToken + 1, false); + + Packet pkt; + pkt.WriteMessageHeader(rage::netMessage::Type::ScriptVerifyHostAck); + net_component->m_ScriptHandler->GetId()->Serialize(&pkt.GetBuffer()); + pkt.GetBuffer().Write(true, 1); + pkt.GetBuffer().Write(true, 1); + pkt.GetBuffer().Write(net_component->m_HostToken, 16); + + for (auto& player : Players::GetPlayers()) + if (!player.second.IsLocal()) + pkt.Send(player.second.GetMessageId()); + } + } } \ No newline at end of file diff --git a/src/game/gta/Scripts.hpp b/src/game/gta/Scripts.hpp index dee9604..03c5ebf 100644 --- a/src/game/gta/Scripts.hpp +++ b/src/game/gta/Scripts.hpp @@ -13,4 +13,5 @@ namespace YimMenu::Scripts extern void RunAsScript(rage::scrThread* thread, std::function callback); extern void RunWithSpoofedThreadName(std::uint32_t name, std::function callback); // consider using RunAsScript if possible extern bool SafeToModifyFreemodeBroadcastGlobals(); // TODO: find a better method for this that works for all scripts + extern void ForceScriptHost(rage::scrThread* thread); // likely unstable, beware! } \ No newline at end of file diff --git a/src/types/script/CGameScriptHandlerNetComponent.hpp b/src/types/script/CGameScriptHandlerNetComponent.hpp new file mode 100644 index 0000000..a54dd35 --- /dev/null +++ b/src/types/script/CGameScriptHandlerNetComponent.hpp @@ -0,0 +1,105 @@ +#pragma once +#include "scriptHandlerNetComponent.hpp" + +class CNetGamePlayer; +class MsgScriptNewHost; + +struct CScriptParticipant +{ + CScriptParticipant* m_Next; + CScriptParticipant* m_Prev; + CNetGamePlayer* m_Player; + std::uint16_t m_ParticipantId; + std::uint16_t m_SlotNumber; + int m_JoinTime; + char gap20[8]; +}; + +// TODO: verify if this is correct in Enhanced +class CGameScriptHandlerNetComponent : public rage::scriptHandlerNetComponent +{ +public: + virtual ~CGameScriptHandlerNetComponent() override = default; + + virtual bool Update() = 0; + virtual void _0x10(CNetGamePlayer*) = 0; // creates a scriptId? + virtual void* PlayerLeft(CNetGamePlayer* player) = 0; + virtual void* SendHostMigrationEvent(CNetGamePlayer* player) = 0; + virtual void PlayerJoined(void**, void* msg_ctx) = 0; + virtual void PlayerJoinedAck(void**, void* msg_ctx) = 0; + virtual void PlayerJoinedHostAck(void*, void*) = 0; + virtual void* _0x40(void*, void*) = 0; // ... + virtual void* _0x48(void*, void*, void*) = 0; + virtual void* _0x50(void*, void*) = 0; + virtual void* _0x58(void*, void*) = 0; + virtual void* _0x60(void*, void*) = 0; + virtual void* _0x68(void*, void*) = 0; + virtual void _0x70(void*, void*) = 0; + virtual void _0x78(void*, void*) = 0; + virtual short _0x80(void*, void*) = 0; + virtual void* _0x88(void*, void*) = 0; + virtual void* _0x90(void*, void*) = 0; + virtual bool _0x98(void*, void*) = 0; + virtual void* _0xA0(void*, void*) = 0; + virtual void* _0xA8(void*, void*) = 0; + virtual short _0xB0(void*, void*) = 0; + virtual bool RegisterHostBroadcastData(void* data, int size, char* a3) = 0; + virtual bool RegisterPlayerBroadcastData(int a1, int size, bool a3) = 0; + virtual bool _0xC8() = 0; + virtual bool _0xD0() = 0; + virtual bool AddPlayerToScript(CNetGamePlayer* player, short* out_participant_id, short* out_slot_number, int* out_fail_reason) = 0; + virtual bool AddPlayerToScriptInternal(CNetGamePlayer* player, short participant_id, short slot_number) = 0; + virtual bool RemovePlayerFromScript(CNetGamePlayer* player) = 0; + virtual void* PlayerLeftImpl(CNetGamePlayer*, bool) = 0; + virtual bool DoHostMigration(CNetGamePlayer* player, short host_token, bool unk) = 0; + virtual void* LeaveFromScript() = 0; + virtual bool _0x108() = 0; + virtual void* _0x110() = 0; + virtual bool _0x118() = 0; // related to above function + + int m_State; + int m_AckPendingPlayers; + CScriptParticipant* m_FirstParticipant; + char gap20[16]; + CScriptParticipant* m_Host; + std::int16_t m_LocalSlotNumber; + char pad_003A[6]; + unsigned int m_ParticipantBitset; + uint16_t m_HostToken; + CNetGamePlayer* m_LastHost; + CNetGamePlayer* m_NextHost; + CNetGamePlayer* m_UnkHost; + char gap60[8]; + MsgScriptNewHost* m_QueuedNewHostMessage; // added b3407, queues a host message if a tunable is enabled and verifies it? + CScriptParticipant* m_Participants[32]; + char pad_0168[8]; + int m_NextHostVerifyTime; + char m_MaxParticipants; + char pad_0175[23]; + uint8_t m_NumParticipants; + uint8_t m_NumCandidates; + uint8_t m_HostAckError; + uint8_t m_HostArrayCount; + uint8_t m_PlayerArrayCount; + uint8_t m_HostMigrationState; + std::uint8_t m_Flags; + char pad_0193[13]; + char m_ScriptStatusQueried; + + inline bool IsLocalPlayerHost() const + { + if (!m_Host) + return true; // or return false? + + return m_Host->m_SlotNumber == m_LocalSlotNumber; + } + + inline CNetGamePlayer* GetHost() const + { + if (!m_Host) + return nullptr; + + return m_Host->m_Player; + } +}; +static_assert(sizeof(CGameScriptHandlerNetComponent) == 0x1B0); \ No newline at end of file diff --git a/src/types/script/scriptHandlerNetComponent.hpp b/src/types/script/scriptHandlerNetComponent.hpp new file mode 100644 index 0000000..f25a7ef --- /dev/null +++ b/src/types/script/scriptHandlerNetComponent.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace rage +{ + class scriptHandler; + class scriptHandlerNetComponent + { + public: + virtual ~scriptHandlerNetComponent() = default; + + public: + scriptHandler* m_ScriptHandler; // 0x08 + }; + static_assert(sizeof(scriptHandlerNetComponent) == 0x10); +} \ No newline at end of file