From 478f21da3df3cbe3fdbd66b2011b3bbe981e84e1 Mon Sep 17 00:00:00 2001 From: Rxann <80224521+Rxann@users.noreply.github.com> Date: Sat, 27 Jul 2024 22:45:24 -0400 Subject: [PATCH] changes --- CMakeLists.txt | 4 +- cmake/rdr-classes.cmake | 14 +- src/core/commands/Vector3Command.cpp | 47 + src/core/commands/Vector3Command.hpp | 22 + src/core/frontend/widgets/imgui_colors.h | 150 ++ src/core/hooking/Hooking.cpp | 3 + src/core/renderer/Renderer.cpp | 197 +-- src/core/renderer/Renderer.hpp | 38 +- src/game/backend/Detections.hpp | 30 + src/game/backend/PersistentPlayerData.hpp | 36 + src/game/backend/PlayerData.hpp | 3 + src/game/backend/PlayerDatabase.cpp | 163 +++ src/game/backend/PlayerDatabase.hpp | 76 + src/game/backend/Players.cpp | 48 +- src/game/backend/Players.hpp | 6 + src/game/backend/SavedLocations.cpp | 112 ++ src/game/backend/SavedLocations.hpp | 66 + src/game/features/network/JoinNewSession.cpp | 41 + .../players/teleport/TpPlayerToMadamNazar.cpp | 24 + src/game/features/players/toxic/Circus.cpp | 9 +- .../features/players/toxic/RemoteBolas.cpp | 56 + .../players/toxic/SendStableEvent.cpp | 2 +- src/game/features/self/Freecam.cpp | 145 ++ src/game/features/system/Chat.cpp | 2 +- src/game/features/world/Bring.cpp | 61 + src/game/features/world/Delete.cpp | 50 + src/game/frontend/ContextMenu.cpp | 39 +- src/game/frontend/ContextMenus.hpp | 65 +- src/game/frontend/ESP.cpp | 43 +- src/game/frontend/items/CommandItem.cpp | 7 +- src/game/frontend/items/Items.hpp | 20 +- src/game/frontend/items/PlayerCommandItem.cpp | 7 +- .../frontend/items/Vector3CommandItem.cpp | 120 ++ src/game/frontend/submenus/Network.cpp | 59 +- src/game/frontend/submenus/Players.cpp | 159 +- src/game/frontend/submenus/Self.cpp | 15 +- src/game/frontend/submenus/Settings.cpp | 26 +- src/game/frontend/submenus/Teleport.cpp | 82 +- src/game/frontend/submenus/World.cpp | 21 +- .../frontend/submenus/World/PedSpawner.cpp | 86 +- src/game/frontend/submenus/World/Shows.cpp | 316 +++- src/game/frontend/submenus/World/Train.cpp | 91 ++ src/game/frontend/submenus/World/Train.hpp | 6 + .../submenus/World/VehicleSpawner.cpp | 5 +- src/game/frontend/submenus/World/weather.hpp | 2 +- src/game/hooks/Hooks.hpp | 6 + src/game/hooks/Info/HandleSessionEvent.cpp | 41 + .../hooks/Protections/HandleNetGameEvent.cpp | 48 +- .../hooks/Protections/HandlePresenceEvent.cpp | 8 +- .../hooks/Protections/ReceiveArrayUpdate.cpp | 4 +- .../hooks/Protections/ReceiveNetMessage.cpp | 19 +- .../hooks/Protections/ShouldBlockSync.cpp | 210 +-- src/game/hooks/Spoofing/GetDiscriminator.cpp | 39 + src/game/pointers/Pointers.cpp | 20 + src/game/pointers/Pointers.hpp | 10 + src/game/rdr/Entity.cpp | 50 +- src/game/rdr/Entity.hpp | 5 +- src/game/rdr/Enums.hpp | 14 +- src/game/rdr/Natives.hpp | 4 +- src/game/rdr/Network.cpp | 67 + src/game/rdr/Network.hpp | 6 + src/game/rdr/Nodes.cpp | 1281 +++++++++-------- src/game/rdr/Ped.cpp | 44 +- src/game/rdr/Ped.hpp | 2 +- src/game/rdr/Player.cpp | 149 +- src/game/rdr/Player.hpp | 34 +- src/game/rdr/Vehicle.cpp | 47 + src/game/rdr/Vehicle.hpp | 13 + src/game/rdr/data/Trains.hpp | 22 + src/main.cpp | 6 +- src/util/Rewards.hpp | 6 +- src/util/teleport.hpp | 21 +- 72 files changed, 3539 insertions(+), 1211 deletions(-) create mode 100644 src/core/commands/Vector3Command.cpp create mode 100644 src/core/commands/Vector3Command.hpp create mode 100644 src/core/frontend/widgets/imgui_colors.h create mode 100644 src/game/backend/Detections.hpp create mode 100644 src/game/backend/PersistentPlayerData.hpp create mode 100644 src/game/backend/PlayerDatabase.cpp create mode 100644 src/game/backend/PlayerDatabase.hpp create mode 100644 src/game/backend/SavedLocations.cpp create mode 100644 src/game/backend/SavedLocations.hpp create mode 100644 src/game/features/network/JoinNewSession.cpp create mode 100644 src/game/features/players/teleport/TpPlayerToMadamNazar.cpp create mode 100644 src/game/features/players/toxic/RemoteBolas.cpp create mode 100644 src/game/features/self/Freecam.cpp create mode 100644 src/game/features/world/Bring.cpp create mode 100644 src/game/features/world/Delete.cpp create mode 100644 src/game/frontend/items/Vector3CommandItem.cpp create mode 100644 src/game/frontend/submenus/World/Train.cpp create mode 100644 src/game/frontend/submenus/World/Train.hpp create mode 100644 src/game/hooks/Info/HandleSessionEvent.cpp create mode 100644 src/game/hooks/Spoofing/GetDiscriminator.cpp create mode 100644 src/game/rdr/Network.cpp create mode 100644 src/game/rdr/Network.hpp create mode 100644 src/game/rdr/Vehicle.cpp create mode 100644 src/game/rdr/Vehicle.hpp create mode 100644 src/game/rdr/data/Trains.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aded266..844e7e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,12 +30,12 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${imgui_SOURCE_DIR}" "${minhook_SOURCE_DIR}/include" "${minhook_SOURCE_DIR}/src/hde" - "${rdr_classes_SOURCE_DIR}" + "${RDR-Classes_SOURCE_DIR}" "${vulkan_SOURCE_DIR}/include" ) message(STATUS "Setting up linked libraries") -target_link_libraries(${PROJECT_NAME} PRIVATE AsyncLogger imgui minhook nlohmann_json::nlohmann_json dbghelp "${DEPS_DIR}/vulkan-1.lib") +target_link_libraries(${PROJECT_NAME} PRIVATE AsyncLogger imgui minhook nlohmann_json::nlohmann_json dbghelp RDR-Classes "${DEPS_DIR}/vulkan-1.lib") add_compile_definitions(${PROJECT_NAME} "_CRT_SECURE_NO_WARNINGS" "NOMINMAX" "WIN32_LEAN_AND_MEAN") diff --git a/cmake/rdr-classes.cmake b/cmake/rdr-classes.cmake index 58afff79..e3324e28 100644 --- a/cmake/rdr-classes.cmake +++ b/cmake/rdr-classes.cmake @@ -1,14 +1,12 @@ include(FetchContent) +message(STATUS "RDR-Classes") + FetchContent_Declare( - rdr_classes + RDR-Classes GIT_REPOSITORY https://github.com/YimMenu/RDR-Classes.git - GIT_TAG 7c78535a483e85fc714525ddce330b2e776e9b8f + GIT_TAG ec19493aedc48e3fe0860342484058e48204dda2 GIT_PROGRESS TRUE - CONFIGURE_COMMAND "" - BUILD_COMMAND "" ) -message(STATUS "RDR-Classes") -if(NOT rdr_classes_POPULATED) - FetchContent_Populate(rdr_classes) -endif() \ No newline at end of file +FetchContent_MakeAvailable(RDR-Classes) +set_property(TARGET RDR-Classes PROPERTY CXX_STANDARD 23) \ No newline at end of file diff --git a/src/core/commands/Vector3Command.cpp b/src/core/commands/Vector3Command.cpp new file mode 100644 index 00000000..b25d6dcf --- /dev/null +++ b/src/core/commands/Vector3Command.cpp @@ -0,0 +1,47 @@ +#include "Vector3Command.hpp" +#include "game/backend/FiberPool.hpp" // TODO: game import in core + +namespace YimMenu +{ + void Vector3Command::OnCall() + { + } + + void Vector3Command::SaveState(nlohmann::json& value) + { + value = nlohmann::json::object(); + value["x"] = m_State.x; + value["y"] = m_State.y; + value["z"] = m_State.z; + } + + void Vector3Command::LoadState(nlohmann::json& value) + { + if (value.is_object()) + { + m_State.x = value["x"]; + m_State.y = value["y"]; + m_State.z = value["z"]; + } + } + + Vector3Command::Vector3Command(std::string name, std::string label, std::string description, rage::fvector3 def_val) : + Command(name, label, description, 0), + m_State(def_val) + { + } + + rage::fvector3 Vector3Command::GetState() + { + return m_State; + } + + void Vector3Command::SetState(const rage::fvector3& state) + { + FiberPool::Push([this] { + OnChange(); + }); + m_State = state; + MarkDirty(); + } +} \ No newline at end of file diff --git a/src/core/commands/Vector3Command.hpp b/src/core/commands/Vector3Command.hpp new file mode 100644 index 00000000..4683f17a --- /dev/null +++ b/src/core/commands/Vector3Command.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "Command.hpp" +#include + +namespace YimMenu +{ + class Vector3Command : public Command + { + protected: + virtual void OnChange(){}; + virtual void OnCall() override; + virtual void SaveState(nlohmann::json& value) override; + virtual void LoadState(nlohmann::json& value) override; + + rage::fvector3 m_State{}; + + public: + Vector3Command(std::string name, std::string label, std::string description, rage::fvector3 def_val = {}); + rage::fvector3 GetState(); + void SetState(const rage::fvector3& state); + }; +} \ No newline at end of file diff --git a/src/core/frontend/widgets/imgui_colors.h b/src/core/frontend/widgets/imgui_colors.h new file mode 100644 index 00000000..302365c1 --- /dev/null +++ b/src/core/frontend/widgets/imgui_colors.h @@ -0,0 +1,150 @@ +#pragma once +#include "imgui.h" + +namespace ImGui +{ + struct Colors + { + inline static ImColor AliceBlue{0.94f, 0.97f, 1.0f, 1.0f}; // ARGB: #FFF0F8FF + inline static ImColor AntiqueWhite{0.98f, 0.92f, 0.84f, 1.0f}; // ARGB: #FFFAEBD7 + inline static ImColor Aqua{0.0f, 1.0f, 1.0f, 1.0f}; // ARGB: #FF00FFFF + inline static ImColor Aquamarine{0.50f, 1.0f, 0.83f, 1.0f}; // ARGB: #FF7FFFD4 + inline static ImColor Azure{0.94f, 1.0f, 1.0f, 1.0f}; // ARGB: #FFF0FFFF + inline static ImColor Beige{0.96f, 0.96f, 0.86f, 1.0f}; // ARGB: #FFF5F5DC + inline static ImColor Bisque{1.0f, 0.89f, 0.77f, 1.0f}; // ARGB: #FFFFE4C4 + inline static ImColor Black{0.0f, 0.0f, 0.0f, 1.0f}; // ARGB: #FF000000 + inline static ImColor BlanchedAlmond{1.0f, 0.92f, 0.80f, 1.0f}; // ARGB: #FFFFEBCD + inline static ImColor Blue{0.0f, 0.0f, 1.0f, 1.0f}; // ARGB: #FF0000FF + inline static ImColor BlueViolet{0.54f, 0.17f, 0.89f, 1.0f}; // ARGB: #FF8A2BE2 + inline static ImColor Brown{0.65f, 0.16f, 0.16f, 1.0f}; // ARGB: #FFA52A2A + inline static ImColor BurlyWood{0.87f, 0.72f, 0.53f, 1.0f}; // ARGB: #FFDEB887 + inline static ImColor CadetBlue{0.37f, 0.62f, 0.63f, 1.0f}; // ARGB: #FF5F9EA0 + inline static ImColor Chartreuse{0.50f, 1.0f, 0.0f, 1.0f}; // ARGB: #FF7FFF00 + inline static ImColor Chocolate{0.82f, 0.41f, 0.12f, 1.0f}; // ARGB: #FFD2691E + inline static ImColor Coral{1.0f, 0.50f, 0.31f, 1.0f}; // ARGB: #FFFF7F50 + inline static ImColor CornflowerBlue{0.39f, 0.58f, 0.93f, 1.0f}; // ARGB: #FF6495ED + inline static ImColor Cornsilk{1.0f, 0.97f, 0.86f, 1.0f}; // ARGB: #FFFFF8DC + inline static ImColor Crimson{0.86f, 0.08f, 0.24f, 1.0f}; // ARGB: #FFDC143C + inline static ImColor Cyan{0.0f, 1.0f, 1.0f, 1.0f}; // ARGB: #FF00FFFF + inline static ImColor DarkBlue{0.0f, 0.0f, 0.55f, 1.0f}; // ARGB: #FF00008B + inline static ImColor DarkCyan{0.0f, 0.55f, 0.55f, 1.0f}; // ARGB: #FF008B8B + inline static ImColor DarkGoldenrod{0.72f, 0.53f, 0.04f, 1.0f}; // ARGB: #FFB8860B + inline static ImColor DarkGray{0.66f, 0.66f, 0.66f, 1.0f}; // ARGB: #FFA9A9A9 + inline static ImColor DarkGreen{0.0f, 0.39f, 0.0f, 1.0f}; // ARGB: #FF006400 + inline static ImColor DarkKhaki{0.74f, 0.72f, 0.42f, 1.0f}; // ARGB: #FFBDB76B + inline static ImColor DarkMagenta{0.55f, 0.0f, 0.55f, 1.0f}; // ARGB: #FF8B008B + inline static ImColor DarkOliveGreen{0.33f, 0.42f, 0.18f, 1.0f}; // ARGB: #FF556B2F + inline static ImColor DarkOrange{1.0f, 0.55f, 0.0f, 1.0f}; // ARGB: #FFFF8C00 + inline static ImColor DarkOrchid{0.60f, 0.20f, 0.80f, 1.0f}; // ARGB: #FF9932CC + inline static ImColor DarkRed{0.55f, 0.0f, 0.0f, 1.0f}; // ARGB: #FF8B0000 + inline static ImColor DarkSalmon{0.91f, 0.59f, 0.48f, 1.0f}; // ARGB: #FFE9967A + inline static ImColor DarkSeaGreen{0.56f, 0.74f, 0.56f, 1.0f}; // ARGB: #FF8FBC8F + inline static ImColor DarkSlateBlue{0.28f, 0.24f, 0.55f, 1.0f}; // ARGB: #FF483D8B + inline static ImColor DarkSlateGray{0.18f, 0.31f, 0.31f, 1.0f}; // ARGB: #FF2F4F4F + inline static ImColor DarkTurquoise{0.0f, 0.81f, 0.82f, 1.0f}; // ARGB: #FF00CED1 + inline static ImColor DarkViolet{0.58f, 0.0f, 0.83f, 1.0f}; // ARGB: #FF9400D3 + inline static ImColor DeepPink{1.0f, 0.08f, 0.58f, 1.0f}; // ARGB: #FFFF1493 + inline static ImColor DeepSkyBlue{0.0f, 0.75f, 1.0f, 1.0f}; // ARGB: #FF00BFFF + inline static ImColor DimGray{0.41f, 0.41f, 0.41f, 1.0f}; // ARGB: #FF696969 + inline static ImColor DodgerBlue{0.12f, 0.56f, 1.0f, 1.0f}; // ARGB: #FF1E90FF + inline static ImColor Firebrick{0.70f, 0.13f, 0.13f, 1.0f}; // ARGB: #FFB22222 + inline static ImColor FloralWhite{1.0f, 0.98f, 0.94f, 1.0f}; // ARGB: #FFFAF0E6 + inline static ImColor ForestGreen{0.13f, 0.55f, 0.13f, 1.0f}; // ARGB: #FF228B22 + inline static ImColor Fuchsia{1.0f, 0.0f, 1.0f, 1.0f}; // ARGB: #FFFF00FF + inline static ImColor Gainsboro{0.86f, 0.86f, 0.86f, 1.0f}; // ARGB: #FFDCDCDC + inline static ImColor GhostWhite{0.97f, 0.97f, 1.0f, 1.0f}; // ARGB: #FFF8F8FF + inline static ImColor Gold{1.0f, 0.84f, 0.0f, 1.0f}; // ARGB: #FFFFD700 + inline static ImColor Goldenrod{0.85f, 0.65f, 0.13f, 1.0f}; // ARGB: #FFDAA520 + inline static ImColor Gray{0.50f, 0.50f, 0.50f, 1.0f}; // ARGB: #FF808080 + inline static ImColor Green{0.0f, 0.50f, 0.0f, 1.0f}; // ARGB: #FF008000 + inline static ImColor GreenYellow{0.68f, 1.0f, 0.18f, 1.0f}; // ARGB: #FFADFF2F + inline static ImColor Honeydew{0.94f, 1.0f, 0.94f, 1.0f}; // ARGB: #FFF0FFF0 + inline static ImColor HotPink{1.0f, 0.41f, 0.71f, 1.0f}; // ARGB: #FFFF69B4 + inline static ImColor IndianRed{0.80f, 0.36f, 0.36f, 1.0f}; // ARGB: #FFCD5C5C + inline static ImColor Indigo{0.29f, 0.0f, 0.51f, 1.0f}; // ARGB: #FF4B0082 + inline static ImColor Ivory{1.0f, 1.0f, 0.94f, 1.0f}; // ARGB: #FFFFFFF0 + inline static ImColor Khaki{0.94f, 0.90f, 0.55f, 1.0f}; // ARGB: #FFF0E68C + inline static ImColor Lavender{0.90f, 0.90f, 0.98f, 1.0f}; // ARGB: #FFE6E6FA + inline static ImColor LavenderBlush{1.0f, 0.94f, 0.96f, 1.0f}; // ARGB: #FFFFF0F5 + inline static ImColor LawnGreen{0.49f, 0.99f, 0.0f, 1.0f}; // ARGB: #FF7CFC00 + inline static ImColor LemonChiffon{1.0f, 0.98f, 0.80f, 1.0f}; // ARGB: #FFFFFACD + inline static ImColor LightBlue{0.68f, 0.85f, 0.90f, 1.0f}; // ARGB: #FFADD8E6 + inline static ImColor LightCoral{0.94f, 0.50f, 0.50f, 1.0f}; // ARGB: #FFF08080 + inline static ImColor LightCyan{0.88f, 1.0f, 1.0f, 1.0f}; // ARGB: #FFE0FFFF + inline static ImColor LightGoldenrodYellow{0.98f, 0.98f, 0.82f, 1.0f}; // ARGB: #FFFAFAD2 + inline static ImColor LightGray{0.83f, 0.83f, 0.83f, 1.0f}; // ARGB: #FFD3D3D3 + inline static ImColor LightGreen{0.56f, 0.93f, 0.56f, 1.0f}; // ARGB: #FF90EE90 + inline static ImColor LightPink{1.0f, 0.71f, 0.76f, 1.0f}; // ARGB: #FFFFB6C1 + inline static ImColor LightSalmon{1.0f, 0.63f, 0.48f, 1.0f}; // ARGB: #FFFFA07A + inline static ImColor LightSeaGreen{0.13f, 0.70f, 0.67f, 1.0f}; // ARGB: #FF20B2AA + inline static ImColor LightSkyBlue{0.53f, 0.81f, 0.98f, 1.0f}; // ARGB: #FF87CEFA + inline static ImColor LightSlateGray{0.47f, 0.53f, 0.60f, 1.0f}; // ARGB: #FF778899 + inline static ImColor LightSteelBlue{0.69f, 0.77f, 0.87f, 1.0f}; // ARGB: #FFB0C4DE + inline static ImColor LightYellow{1.0f, 1.0f, 0.88f, 1.0f}; // ARGB: #FFFFFFE0 + inline static ImColor Lime{0.0f, 1.0f, 0.0f, 1.0f}; // ARGB: #FF00FF00 + inline static ImColor LimeGreen{0.20f, 0.80f, 0.20f, 1.0f}; // ARGB: #FF32CD32 + inline static ImColor Linen{0.98f, 0.94f, 0.90f, 1.0f}; // ARGB: #FFFAF0E6 + inline static ImColor Magenta{1.0f, 0.0f, 1.0f, 1.0f}; // ARGB: #FFFF00FF + inline static ImColor Maroon{0.50f, 0.0f, 0.0f, 1.0f}; // ARGB: #FF800000 + inline static ImColor MediumAquamarine{0.40f, 0.80f, 0.67f, 1.0f}; // ARGB: #FF66CDAA + inline static ImColor MediumBlue{0.0f, 0.0f, 0.80f, 1.0f}; // ARGB: #FF0000CD + inline static ImColor MediumOrchid{0.73f, 0.33f, 0.83f, 1.0f}; // ARGB: #FFBA55D3 + inline static ImColor MediumPurple{0.58f, 0.44f, 0.86f, 1.0f}; // ARGB: #FF9370DB + inline static ImColor MediumSeaGreen{0.24f, 0.70f, 0.44f, 1.0f}; // ARGB: #FF3CB371 + inline static ImColor MediumSlateBlue{0.48f, 0.41f, 0.93f, 1.0f}; // ARGB: #FF7B68EE + inline static ImColor MediumSpringGreen{0.0f, 0.98f, 0.60f, 1.0f}; // ARGB: #FF00FA9A + inline static ImColor MediumTurquoise{0.28f, 0.82f, 0.80f, 1.0f}; // ARGB: #FF48D1CC + inline static ImColor MediumVioletRed{0.78f, 0.08f, 0.52f, 1.0f}; // ARGB: #FFC71585 + inline static ImColor MidnightBlue{0.10f, 0.10f, 0.44f, 1.0f}; // ARGB: #FF191970 + inline static ImColor MintCream{0.96f, 1.0f, 0.98f, 1.0f}; // ARGB: #FFF5FFFA + inline static ImColor MistyRose{1.0f, 0.89f, 0.88f, 1.0f}; // ARGB: #FFFFE4E1 + inline static ImColor Moccasin{1.0f, 0.89f, 0.71f, 1.0f}; // ARGB: #FFFFE4B5 + inline static ImColor NavajoWhite{1.0f, 0.87f, 0.68f, 1.0f}; // ARGB: #FFFFDEAD + inline static ImColor Navy{0.0f, 0.0f, 0.50f, 1.0f}; // ARGB: #FF000080 + inline static ImColor OldLace{0.99f, 0.96f, 0.90f, 1.0f}; // ARGB: #FFFDF5E6 + inline static ImColor Olive{0.50f, 0.50f, 0.0f, 1.0f}; // ARGB: #FF808000 + inline static ImColor OliveDrab{0.42f, 0.56f, 0.14f, 1.0f}; // ARGB: #FF6B8E23 + inline static ImColor Orange{1.0f, 0.65f, 0.0f, 1.0f}; // ARGB: #FFFFA500 + inline static ImColor OrangeRed{1.0f, 0.27f, 0.0f, 1.0f}; // ARGB: #FFFF4500 + inline static ImColor Orchid{0.85f, 0.44f, 0.84f, 1.0f}; // ARGB: #FFDA70D6 + inline static ImColor PaleGoldenrod{0.93f, 0.91f, 0.67f, 1.0f}; // ARGB: #FFEEE8AA + inline static ImColor PaleGreen{0.60f, 0.98f, 0.60f, 1.0f}; // ARGB: #FF98FB98 + inline static ImColor PaleTurquoise{0.69f, 0.93f, 0.93f, 1.0f}; // ARGB: #FFAFEEEE + inline static ImColor PaleVioletRed{0.86f, 0.44f, 0.58f, 1.0f}; // ARGB: #FFDB7093 + inline static ImColor PapayaWhip{1.0f, 0.94f, 0.84f, 1.0f}; // ARGB: #FFFFEFD5 + inline static ImColor PeachPuff{1.0f, 0.85f, 0.73f, 1.0f}; // ARGB: #FFFFDAB9 + inline static ImColor Peru{0.80f, 0.52f, 0.25f, 1.0f}; // ARGB: #FFCD853F + inline static ImColor Pink{1.0f, 0.75f, 0.80f, 1.0f}; // ARGB: #FFFFC0CB + inline static ImColor Plum{0.87f, 0.63f, 0.87f, 1.0f}; // ARGB: #FFDDA0DD + inline static ImColor PowderBlue{0.69f, 0.88f, 0.90f, 1.0f}; // ARGB: #FFB0E0E6 + inline static ImColor Purple{0.50f, 0.0f, 0.50f, 1.0f}; // ARGB: #FF800080 + inline static ImColor Red{1.0f, 0.0f, 0.0f, 1.0f}; // ARGB: #FFFF0000 + inline static ImColor RosyBrown{0.74f, 0.56f, 0.56f, 1.0f}; // ARGB: #FFBC8F8F + inline static ImColor RoyalBlue{0.25f, 0.41f, 0.88f, 1.0f}; // ARGB: #FF4169E1 + inline static ImColor SaddleBrown{0.55f, 0.27f, 0.07f, 1.0f}; // ARGB: #FF8B4513 + inline static ImColor Salmon{0.98f, 0.50f, 0.45f, 1.0f}; // ARGB: #FFFA8072 + inline static ImColor SandyBrown{0.96f, 0.64f, 0.38f, 1.0f}; // ARGB: #FFF4A460 + inline static ImColor SeaGreen{0.18f, 0.55f, 0.34f, 1.0f}; // ARGB: #FF2E8B57 + inline static ImColor SeaShell{1.0f, 0.96f, 0.93f, 1.0f}; // ARGB: #FFFFF5EE + inline static ImColor Sienna{0.63f, 0.32f, 0.18f, 1.0f}; // ARGB: #FFA0522D + inline static ImColor Silver{0.75f, 0.75f, 0.75f, 1.0f}; // ARGB: #FFC0C0C0 + inline static ImColor SkyBlue{0.53f, 0.81f, 0.92f, 1.0f}; // ARGB: #FF87CEEB + inline static ImColor SlateBlue{0.42f, 0.35f, 0.80f, 1.0f}; // ARGB: #FF6A5ACD + inline static ImColor SlateGray{0.44f, 0.50f, 0.56f, 1.0f}; // ARGB: #FF708090 + inline static ImColor Snow{1.0f, 0.98f, 0.98f, 1.0f}; // ARGB: #FFFFFAFA + inline static ImColor SpringGreen{0.0f, 1.0f, 0.50f, 1.0f}; // ARGB: #FF00FF7F + inline static ImColor SteelBlue{0.27f, 0.51f, 0.71f, 1.0f}; // ARGB: #FF4682B4 + inline static ImColor Tan{0.82f, 0.71f, 0.55f, 1.0f}; // ARGB: #FFD2B48C + inline static ImColor Teal{0.0f, 0.50f, 0.50f, 1.0f}; // ARGB: #FF008080 + inline static ImColor Thistle{0.85f, 0.75f, 0.85f, 1.0f}; // ARGB: #FFD8BFD8 + inline static ImColor Tomato{1.0f, 0.39f, 0.28f, 1.0f}; // ARGB: #FFFF6347 + inline static ImColor Transparent{1.0f, 1.0f, 1.0f, 0.0f}; // ARGB: #00FFFFFF + inline static ImColor Turquoise{0.25f, 0.88f, 0.82f, 1.0f}; // ARGB: #FF40E0D0 + inline static ImColor Violet{0.93f, 0.51f, 0.93f, 1.0f}; // ARGB: #FFEE82EE + inline static ImColor Wheat{0.96f, 0.87f, 0.70f, 1.0f}; // ARGB: #FFF5DEB3 + inline static ImColor White{1.0f, 1.0f, 1.0f, 1.0f}; // ARGB: #FFFFFFFF + inline static ImColor WhiteSmoke{0.96f, 0.96f, 0.96f, 1.0f}; // ARGB: #FFF5F5F5 + inline static ImColor Yellow{1.0f, 1.0f, 0.0f, 1.0f}; // ARGB: #FFFFFF00 + inline static ImColor YellowGreen{0.60f, 0.80f, 0.20f, 1.0f}; // ARGB: #FF9ACD32 + }; +} \ No newline at end of file diff --git a/src/core/hooking/Hooking.cpp b/src/core/hooking/Hooking.cpp index daf2aa36..c4259619 100644 --- a/src/core/hooking/Hooking.cpp +++ b/src/core/hooking/Hooking.cpp @@ -64,9 +64,12 @@ namespace YimMenu BaseHook::Add(new DetourHook("PlayerHasJoined", Pointers.PlayerHasJoined, Hooks::Info::PlayerHasJoined)); BaseHook::Add(new DetourHook("PlayerHasLeft", Pointers.PlayerHasLeft, Hooks::Info::PlayerHasLeft)); + BaseHook::Add(new DetourHook("HandleSessionEvent", Pointers.HandleSessionEvent, Hooks::Info::HandleSessionEvent)); + BaseHook::Add(new DetourHook("WritePlayerHealthData", Pointers.WritePlayerHealthData, Hooks::Spoofing::WritePlayerHealthData)); BaseHook::Add(new DetourHook("SendNetInfoToLobby", Pointers.SendNetInfoToLobby, Hooks::Spoofing::SendNetInfoToLobby)); BaseHook::Add(new DetourHook("WriteVehicleProximityMigrationData", Pointers.WriteVPMData, Hooks::Spoofing::WriteVPMData)); + BaseHook::Add(new DetourHook("GetDiscriminator", Pointers.GetDiscriminator, Hooks::Spoofing::GetDiscriminator)); BaseHook::Add(new DetourHook("BroadcastNetArray", Pointers.BroadcastNetArray, Hooks::Toxic::BroadcastNetArray)); } diff --git a/src/core/renderer/Renderer.cpp b/src/core/renderer/Renderer.cpp index f7729cef..78e00be8 100644 --- a/src/core/renderer/Renderer.cpp +++ b/src/core/renderer/Renderer.cpp @@ -1,10 +1,10 @@ #include "Renderer.hpp" -#include "game/pointers/Pointers.hpp" -#include "game/frontend/GUI.hpp" -#include "game/frontend/Menu.hpp" #include "core/memory/ModuleMgr.hpp" #include "core/memory/PatternScanner.hpp" +#include "game/frontend/GUI.hpp" +#include "game/frontend/Menu.hpp" +#include "game/pointers/Pointers.hpp" #include #include @@ -32,7 +32,6 @@ namespace YimMenu vkDeviceWaitIdle(m_VkDevice); vkDestroyInstance(m_VkInstance, m_VkAllocator); ImGui_ImplVulkan_Shutdown(); - } else if (!Pointers.IsVulkan) { @@ -192,20 +191,18 @@ namespace YimMenu bool Renderer::InitVulkan() { - VkInstanceCreateInfo CreateInfo = {}; + VkInstanceCreateInfo CreateInfo = {}; - const std::vector InstanceExtensions = {"VK_KHR_surface" }; + const std::vector InstanceExtensions = {"VK_KHR_surface"}; - const std::vector ValidationLayers = { - "VK_LAYER_KHRONOS_validation" - }; + const std::vector ValidationLayers = {"VK_LAYER_KHRONOS_validation"}; - CreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + CreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; CreateInfo.enabledExtensionCount = (uint32_t)InstanceExtensions.size(); CreateInfo.ppEnabledExtensionNames = InstanceExtensions.data(); - // CreateInfo.enabledLayerCount = (uint32_t)ValidationLayers.size(); - // CreateInfo.ppEnabledLayerNames = ValidationLayers.data(); + // CreateInfo.enabledLayerCount = (uint32_t)ValidationLayers.size(); + // CreateInfo.ppEnabledLayerNames = ValidationLayers.data(); // Create Vulkan Instance without debug feature if (const VkResult result = vkCreateInstance(&CreateInfo, m_VkAllocator, &m_VkInstance); result != VK_SUCCESS) @@ -214,8 +211,8 @@ namespace YimMenu return false; } -; - uint32_t GpuCount; + ; + uint32_t GpuCount; if (const VkResult result = vkEnumeratePhysicalDevices(m_VkInstance, &GpuCount, NULL); result != VK_SUCCESS) { LOG(WARNING) << "vkEnumeratePhysicalDevices failed with result: [" << result << "]"; @@ -280,7 +277,7 @@ namespace YimMenu DeviceQueueInfo.pQueuePriorities = &QueuePriority; VkDeviceCreateInfo DeviceCreateInfo = {}; - DeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + DeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; DeviceCreateInfo.queueCreateInfoCount = 1; DeviceCreateInfo.pQueueCreateInfos = &DeviceQueueInfo; DeviceCreateInfo.enabledExtensionCount = 1; @@ -309,6 +306,17 @@ namespace YimMenu return true; } + void Renderer::ResizeImpl(float scale) + { + DX12PreResize(); + + if (scale != 1.0f) + ImGui::GetStyle().ScaleAllSizes(scale); + ImGui::GetStyle().MouseCursorScale = 1.0f; + ImGui::GetIO().FontGlobalScale = scale; + DX12PostResize(); + } + void Renderer::VkCreateRenderTarget(VkDevice Device, VkSwapchainKHR Swapchain) { uint32_t uImageCount; @@ -325,24 +333,24 @@ namespace YimMenu return; } - for (uint32_t i = 0; i < uImageCount; ++i) - { - m_VkFrames[i].Backbuffer = BackBuffers[i]; - - ImGui_ImplVulkanH_Frame* fd = &m_VkFrames[i]; - ImGui_ImplVulkanH_FrameSemaphores* fsd = &m_VkFrameSemaphores[i]; - { - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - info.queueFamilyIndex = m_VkQueueFamily; - + for (uint32_t i = 0; i < uImageCount; ++i) + { + m_VkFrames[i].Backbuffer = BackBuffers[i]; + + ImGui_ImplVulkanH_Frame* fd = &m_VkFrames[i]; + ImGui_ImplVulkanH_FrameSemaphores* fsd = &m_VkFrameSemaphores[i]; + { + VkCommandPoolCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + info.queueFamilyIndex = m_VkQueueFamily; + if (const VkResult result = vkCreateCommandPool(Device, &info, m_VkAllocator, &fd->CommandPool)) { LOG(WARNING) << "vkCreateCommandPool failed with result: [" << result << "]"; return; } - } + } { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -381,9 +389,9 @@ namespace YimMenu return; } } - } + } - { + { VkAttachmentDescription attachment = {}; attachment.format = VK_FORMAT_B8G8R8A8_UNORM; attachment.samples = VK_SAMPLE_COUNT_1_BIT; @@ -415,8 +423,8 @@ namespace YimMenu LOG(WARNING) << "vkCreateRenderPass failed with result: [" << result << "]"; return; } - } - { + } + { VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.viewType = VK_IMAGE_VIEW_TYPE_2D; @@ -439,8 +447,8 @@ namespace YimMenu return; } } - } - { + } + { VkImageView attachment[1]; VkFramebufferCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -460,10 +468,10 @@ namespace YimMenu return; } } - } + } - if (!m_VkDescriptorPool) // Create Descriptor Pool. - { + if (!m_VkDescriptorPool) // Create Descriptor Pool. + { constexpr VkDescriptorPoolSize pool_sizes[] = {{VK_DESCRIPTOR_TYPE_SAMPLER, 1000}, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000}, {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000}, {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000}, {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000}, {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000}, {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000}}; VkDescriptorPoolCreateInfo pool_info = {}; @@ -478,13 +486,13 @@ namespace YimMenu LOG(WARNING) << "vkCreateDescriptorPool failed with result: [" << result << "]"; return; } - } + } } void Renderer::VkCleanupRenderTarget() { - for (uint32_t i = 0; i < RTL_NUMBER_OF(GetInstance().m_VkFrames); ++i) - { + for (uint32_t i = 0; i < RTL_NUMBER_OF(GetInstance().m_VkFrames); ++i) + { if (GetInstance().m_VkFrames[i].Fence) { vkDestroyFence(GetInstance().m_VkDevice, GetInstance().m_VkFrames[i].Fence, GetInstance().m_VkAllocator); @@ -492,7 +500,10 @@ namespace YimMenu } if (GetInstance().m_VkFrames[i].CommandBuffer) { - vkFreeCommandBuffers(GetInstance().m_VkDevice, GetInstance().m_VkFrames[i].CommandPool, 1, &GetInstance().m_VkFrames[i].CommandBuffer); + vkFreeCommandBuffers(GetInstance().m_VkDevice, + GetInstance().m_VkFrames[i].CommandPool, + 1, + &GetInstance().m_VkFrames[i].CommandBuffer); GetInstance().m_VkFrames[i].CommandBuffer = VK_NULL_HANDLE; } if (GetInstance().m_VkFrames[i].CommandPool) @@ -510,31 +521,35 @@ namespace YimMenu vkDestroyFramebuffer(GetInstance().m_VkDevice, GetInstance().m_VkFrames[i].Framebuffer, GetInstance().m_VkAllocator); GetInstance().m_VkFrames[i].Framebuffer = VK_NULL_HANDLE; } - } + } - for (uint32_t i = 0; i < RTL_NUMBER_OF(GetInstance().m_VkFrameSemaphores); ++i) - { + for (uint32_t i = 0; i < RTL_NUMBER_OF(GetInstance().m_VkFrameSemaphores); ++i) + { if (GetInstance().m_VkFrameSemaphores[i].ImageAcquiredSemaphore) { - vkDestroySemaphore(GetInstance().m_VkDevice, GetInstance().m_VkFrameSemaphores[i].ImageAcquiredSemaphore, GetInstance().m_VkAllocator); + vkDestroySemaphore(GetInstance().m_VkDevice, + GetInstance().m_VkFrameSemaphores[i].ImageAcquiredSemaphore, + GetInstance().m_VkAllocator); GetInstance().m_VkFrameSemaphores[i].ImageAcquiredSemaphore = VK_NULL_HANDLE; } if (GetInstance().m_VkFrameSemaphores[i].RenderCompleteSemaphore) { - vkDestroySemaphore(GetInstance().m_VkDevice, GetInstance().m_VkFrameSemaphores[i].RenderCompleteSemaphore, GetInstance().m_VkAllocator); + vkDestroySemaphore(GetInstance().m_VkDevice, + GetInstance().m_VkFrameSemaphores[i].RenderCompleteSemaphore, + GetInstance().m_VkAllocator); GetInstance().m_VkFrameSemaphores[i].RenderCompleteSemaphore = VK_NULL_HANDLE; } - } + } - //Reason we have to rescan is when window is resized the HWND changes and Vulkan ImGui does not like this at all. (Grabbing from IDXGISwapchain does not work, it simply doesn't update or is too slow in my testing. Feel free) - if (IsResizing()) - { + //Reason we have to rescan is when window is resized the HWND changes and Vulkan ImGui does not like this at all. (Grabbing from IDXGISwapchain does not work, it simply doesn't update or is too slow in my testing. Feel free) + if (IsResizing()) + { ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); const auto rdr2 = ModuleMgr.Get("RDR2.exe"_J); - auto scanner = PatternScanner(rdr2); + auto scanner = PatternScanner(rdr2); constexpr auto hwnd = Pattern<"4C 8B 05 ? ? ? ? 4C 8D 0D ? ? ? ? 48 89 54 24">("Hwnd"); scanner.Add(hwnd, [](PointerCalculator ptr) { @@ -548,19 +563,19 @@ namespace YimMenu return; } - + ImGui::CreateContext(&GetInstance().m_FontAtlas); ImGui_ImplWin32_Init(Pointers.Hwnd); Menu::SetupStyle(); SetResizing(false); - } + } } bool Renderer::DoesQueueSupportGraphic(VkQueue queue, VkQueue* pGraphicQueue) { - for (uint32_t i = 0; i < m_VKQueueFamilies.size(); ++i) - { + for (uint32_t i = 0; i < m_VKQueueFamilies.size(); ++i) + { const VkQueueFamilyProperties& family = m_VKQueueFamilies[i]; for (uint32_t j = 0; j < family.queueCount; ++j) { @@ -581,29 +596,29 @@ namespace YimMenu return true; } } - } + } - return false; - } + return false; + } void Renderer::VkOnPresentImpl(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { - if (!m_VkDevice || !g_Running || IsResizing()) - { + if (!m_VkDevice || !g_Running || IsResizing()) + { return; - } + } - if (!ImGui::GetCurrentContext()) - { + if (!ImGui::GetCurrentContext()) + { ImGui::CreateContext(&GetInstance().m_FontAtlas); ImGui_ImplWin32_Init(Pointers.Hwnd); - } + } - VkQueue GraphicQueue = VK_NULL_HANDLE; - const bool QueueSupportsGraphic = DoesQueueSupportGraphic(queue, &GraphicQueue); + VkQueue GraphicQueue = VK_NULL_HANDLE; + const bool QueueSupportsGraphic = DoesQueueSupportGraphic(queue, &GraphicQueue); - for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) - { + for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) + { VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i]; if (m_VkFrames[0].Framebuffer == VK_NULL_HANDLE) { @@ -630,7 +645,7 @@ namespace YimMenu { LOG(WARNING) << "vkResetCommandBuffer failed with result: [" << result << "]"; return; - } + } VkCommandBufferBeginInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -675,8 +690,8 @@ namespace YimMenu init_info.ImageCount = m_VkMinImageCount; init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; init_info.Allocator = m_VkAllocator; - - ImGui_ImplVulkan_Init(&init_info, m_VkRenderPass); + + ImGui_ImplVulkan_Init(&init_info, m_VkRenderPass); ImGui_ImplVulkan_CreateFontsTexture(fd->CommandBuffer); } @@ -686,7 +701,7 @@ namespace YimMenu ImGui::NewFrame(); for (const auto& callback : m_RendererCallBacks | std::views::values) - callback(); + callback(); ImGui::Render(); @@ -756,11 +771,11 @@ namespace YimMenu return; } } - } + } } - bool Renderer::InitImpl() + bool Renderer::InitImpl() { if (Pointers.IsVulkan) { @@ -771,7 +786,7 @@ namespace YimMenu { LOG(INFO) << "Using DX12, clear shader cache if your having issues."; LOG(INFO) << "Waiting..."; - std::this_thread::sleep_for(5s); //Early injection could result in errors. + std::this_thread::sleep_for(5s); //Early injection could result in errors. return InitDX12(); } @@ -829,20 +844,20 @@ namespace YimMenu void Renderer::WaitForNextFrame() { - UINT NextFrameIndex = GetInstance().m_FrameIndex + 1; + UINT NextFrameIndex = GetInstance().m_FrameIndex + 1; GetInstance().m_FrameIndex = NextFrameIndex; - HANDLE WaitableObjects[] = { GetInstance().m_SwapchainWaitableObject, nullptr}; - DWORD NumWaitableObjets = 1; + HANDLE WaitableObjects[] = {GetInstance().m_SwapchainWaitableObject, nullptr}; + DWORD NumWaitableObjets = 1; FrameContext FrameCtx = GetInstance().m_FrameContext[NextFrameIndex % GetInstance().m_SwapChainDesc.BufferCount]; - UINT64 FenceValue = FrameCtx.FenceValue; + UINT64 FenceValue = FrameCtx.FenceValue; if (FenceValue != 0) // means no fence was signaled { FrameCtx.FenceValue = 0; GetInstance().m_Fence->SetEventOnCompletion(FenceValue, GetInstance().m_FenceEvent); - WaitableObjects[1] = GetInstance().m_FenceEvent; - NumWaitableObjets = 2; + WaitableObjects[1] = GetInstance().m_FenceEvent; + NumWaitableObjets = 2; } WaitForMultipleObjects(NumWaitableObjets, WaitableObjects, TRUE, INFINITE); @@ -854,7 +869,7 @@ namespace YimMenu WaitForLastFrame(); - ImGui_ImplDX12_InvalidateDeviceObjects(); + ImGui_ImplDX12_InvalidateDeviceObjects(); for (size_t i{}; i != GetInstance().m_SwapChainDesc.BufferCount; ++i) { @@ -865,9 +880,9 @@ namespace YimMenu void Renderer::DX12PostResize() { //Recreate our pointers and ImGui's - ImGui_ImplDX12_CreateDeviceObjects(); - const auto RTVDescriptorSize{ GetInstance().m_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV) }; - D3D12_CPU_DESCRIPTOR_HANDLE RTVHandle{ GetInstance().m_BackbufferDescriptorHeap->GetCPUDescriptorHandleForHeapStart() }; + ImGui_ImplDX12_CreateDeviceObjects(); + const auto RTVDescriptorSize{GetInstance().m_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV)}; + D3D12_CPU_DESCRIPTOR_HANDLE RTVHandle{GetInstance().m_BackbufferDescriptorHeap->GetCPUDescriptorHandleForHeapStart()}; for (size_t i{}; i != GetInstance().m_SwapChainDesc.BufferCount; ++i) { ComPtr BackBuffer{}; @@ -892,10 +907,12 @@ namespace YimMenu { WaitForNextFrame(); - FrameContext& CurrentFrameContext{ GetInstance().m_FrameContext[GetInstance().m_SwapChain->GetCurrentBackBufferIndex()] }; + FrameContext& CurrentFrameContext{GetInstance().m_FrameContext[GetInstance().m_SwapChain->GetCurrentBackBufferIndex()]}; CurrentFrameContext.CommandAllocator->Reset(); - D3D12_RESOURCE_BARRIER Barrier{ D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, { { CurrentFrameContext.Resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET } } }; + D3D12_RESOURCE_BARRIER Barrier{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, + D3D12_RESOURCE_BARRIER_FLAG_NONE, + {{CurrentFrameContext.Resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET}}}; GetInstance().m_CommandList->Reset(CurrentFrameContext.CommandAllocator, nullptr); GetInstance().m_CommandList->ResourceBarrier(1, &Barrier); GetInstance().m_CommandList->OMSetRenderTargets(1, &CurrentFrameContext.Descriptor, FALSE, nullptr); @@ -905,16 +922,16 @@ namespace YimMenu ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), GetInstance().m_CommandList.Get()); Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; - Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; GetInstance().m_CommandList->ResourceBarrier(1, &Barrier); GetInstance().m_CommandList->Close(); - ID3D12CommandList* CommandLists[]{ GetInstance().m_CommandList.Get() }; + ID3D12CommandList* CommandLists[]{GetInstance().m_CommandList.Get()}; GetInstance().m_CommandQueue->ExecuteCommandLists(_countof(CommandLists), CommandLists); UINT64 FenceValue = GetInstance().m_FenceLastSignaledValue + 1; GetInstance().m_CommandQueue->Signal(GetInstance().m_Fence.Get(), FenceValue); GetInstance().m_FenceLastSignaledValue = FenceValue; - CurrentFrameContext.FenceValue = FenceValue; + CurrentFrameContext.FenceValue = FenceValue; } } \ No newline at end of file diff --git a/src/core/renderer/Renderer.hpp b/src/core/renderer/Renderer.hpp index a5d99a75..6c40f041 100644 --- a/src/core/renderer/Renderer.hpp +++ b/src/core/renderer/Renderer.hpp @@ -1,22 +1,28 @@ #pragma once #include "util/Joaat.hpp" -#include +#include +#include #include +#include #include #include +#include #include #include -#include -#include -#include -#define REL(o) o->Release(); if (o) { o = nullptr; } + +#define REL(o) \ + o->Release(); \ + if (o) \ + { \ + o = nullptr; \ + } namespace YimMenu { using namespace Microsoft::WRL; - using RendererCallBack = std::function; + using RendererCallBack = std::function; using WindowProcedureCallback = std::function; struct FrameContext @@ -82,7 +88,7 @@ namespace YimMenu { LOG(FATAL) << "Invalid Vulkan Queue!"; - return; + return; } if (!pPresentInfo) @@ -107,17 +113,22 @@ namespace YimMenu static void DX12PostResize(); static void VkCleanupRenderTarget(); - + static bool IsResizing() { return GetInstance().m_Resizing; } - static void SetResizing(const bool &status) + static void SetResizing(const bool& status) { GetInstance().m_Resizing = status; } + static void Resize(float scale) + { + GetInstance().ResizeImpl(scale); + } + static void VkSetDevice(VkDevice device) { if (!device) @@ -130,13 +141,14 @@ namespace YimMenu GetInstance().m_VkDevice = device; } static void VkSetScreenSize(VkExtent2D extent) - { + { GetInstance().m_VkImageExtent = extent; } private: static void DX12NewFrame(); static void DX12EndFrame(); + private: void DestroyImpl(); bool InitImpl(); @@ -144,6 +156,8 @@ namespace YimMenu bool InitDX12(); bool InitVulkan(); + void ResizeImpl(float scale); + void VkCreateRenderTarget(VkDevice Device, VkSwapchainKHR Swapchain); bool AddRendererCallBackImpl(RendererCallBack&& callback, std::uint32_t priority); @@ -196,15 +210,15 @@ namespace YimMenu uint32_t m_VkQueueFamily = (uint32_t)-1; VkDevice m_VkFakeDevice; VkDevice m_VkDevice; - ImGui_ImplVulkanH_Frame m_VkFrames[8] = {}; + ImGui_ImplVulkanH_Frame m_VkFrames[8] = {}; ImGui_ImplVulkanH_FrameSemaphores m_VkFrameSemaphores[8] = {}; VkRenderPass m_VkRenderPass; VkDescriptorPool m_VkDescriptorPool; VkPipelineCache m_VkPipelineCache; uint32_t m_VkMinImageCount = 2; VkExtent2D m_VkImageExtent; - private: + private: //Other std::map m_RendererCallBacks; std::vector m_WindowProcedureCallbacks; diff --git a/src/game/backend/Detections.hpp b/src/game/backend/Detections.hpp new file mode 100644 index 00000000..15f3d870 --- /dev/null +++ b/src/game/backend/Detections.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "util/Joaat.hpp" + +namespace YimMenu +{ + enum class Detection : std::uint32_t + { + TRIED_CRASH_PLAYER = "TRIED_CRASH_PLAYER"_J, + TRIED_KICK_PLAYER = "TRIED_KICK_PLAYER"_J, + MODDER_EVENTS = "MODDER_EVENTS"_J, + TRIED_ATTACH = "TRIED_ATTACH"_J, + REMOTE_TELEPORT = "REMOTE_TELEPORT"_J, + INVALID_PLAYER_MODEL = "INVALID_PLAYER_MODEL"_J, + SPOOFING_ROCKSTAR_ID = "SPOOFING_ROCKSTAR_ID"_J, + SPOOFING_IP = "SPOOFING_IP"_J, + SPOOFING_NAME = "SPOOFING_NAME"_J, + }; + + inline const std::unordered_map g_DetectionDescs = { + {Detection::TRIED_CRASH_PLAYER, "Tried to crash you"}, + {Detection::TRIED_KICK_PLAYER, "Tried to kick you"}, + {Detection::MODDER_EVENTS, "Sent modder events"}, + {Detection::TRIED_ATTACH, "Tried to attach to you"}, + {Detection::REMOTE_TELEPORT, "Tried to teleport you"}, + {Detection::INVALID_PLAYER_MODEL, "Used an invalid player model"}, + {Detection::SPOOFING_ROCKSTAR_ID, "Has spoofed their Rockstar ID"}, + {Detection::SPOOFING_IP, "Has spoofed their IP"}, + {Detection::SPOOFING_NAME, "Has spoofed their name"}, + }; +} \ No newline at end of file diff --git a/src/game/backend/PersistentPlayerData.hpp b/src/game/backend/PersistentPlayerData.hpp new file mode 100644 index 00000000..a0f1b919 --- /dev/null +++ b/src/game/backend/PersistentPlayerData.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "util/Joaat.hpp" +#include + +namespace YimMenu +{ + enum class DetectionType : std::uint32_t + { + TRIED_CRASH_PLAYER = "TRIED_CRASH_PLAYER"_J, + TRIED_KICK_PLAYER = "TRIED_KICK_PLAYER"_J, + MODDER_EVENTS = "MODDER_EVENTS"_J, + TRIED_ATTACH = "TRIED_ATTACH"_J, + REMOTE_TELEPORT = "REMOTE_TELEPORT"_J, + INVALID_PLAYER_MODEL = "INVALID_PLAYER_MODEL"_J, + }; + + std::unordered_map g_DetectionDescs = { + {DetectionType::TRIED_CRASH_PLAYER, "Tried to crash you!"}, + {DetectionType::TRIED_KICK_PLAYER, "Tried to kick you!"}, + {DetectionType::MODDER_EVENTS, "Tried to call a native!"}, + {DetectionType::TRIED_ATTACH, "Tried to attach to you!"}, + {DetectionType::REMOTE_TELEPORT, "Tried to teleport to you!"}, + {DetectionType::INVALID_PLAYER_MODEL, "Tried to use an invalid player model!"}, + }; + + struct PersistentPlayerData + { + uint64_t Rid; + std::string Name; + bool BlockJoin = false; + bool Trusted = false; + std::unordered_set Detections; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(PersistentPlayerData, Rid, Name, BlockJoin, Trusted, Detections); + }; +} \ No newline at end of file diff --git a/src/game/backend/PlayerData.hpp b/src/game/backend/PlayerData.hpp index 9c7f8196..ea33698b 100644 --- a/src/game/backend/PlayerData.hpp +++ b/src/game/backend/PlayerData.hpp @@ -1,10 +1,13 @@ #pragma once +#include "Detections.hpp" +#include namespace YimMenu { class PlayerData { public: + std::unordered_set m_Detections{}; bool m_UseSessionSplitKick{}; }; } \ No newline at end of file diff --git a/src/game/backend/PlayerDatabase.cpp b/src/game/backend/PlayerDatabase.cpp new file mode 100644 index 00000000..1127c41a --- /dev/null +++ b/src/game/backend/PlayerDatabase.cpp @@ -0,0 +1,163 @@ +#include "PlayerDatabase.hpp" +#include "Detections.hpp" + +namespace YimMenu +{ + using json = nlohmann::json; + + PlayerDatabase::PlayerDatabase() : + m_File(std::filesystem::path(std::getenv("appdata")) / "HorseMenu" / "database.json") + { + Load(); + + g_PlayerDatabase = this; + + LOG(INFO) << "Player Database Initialized"; + } + + PlayerDatabase::~PlayerDatabase() + { + LOG(INFO) << "Player Database Uninitialized"; + + g_PlayerDatabase = nullptr; + } + + void PlayerDatabase::Load() + { + m_Selected = nullptr; + if (!std::filesystem::exists(m_File)) + { + LOG(VERBOSE) << "Player Database Doesn't Exist"; + std::ofstream file(m_File, std::ios::out | std::ios::trunc); + file << "{}" << std::endl; + file.close(); + + if (!std::filesystem::exists(m_File)) + { + LOG(VERBOSE) << "Player Database unable to open!"; + } + else + LOG(VERBOSE) << "Player Database Reset!"; + } + + std::ifstream fileStream(m_File); + if (fileStream.is_open()) + { + json jsonData; + fileStream >> jsonData; + fileStream.close(); + + for (auto& [key, value] : jsonData.items()) + { + auto player = value.get>(); + m_Data[std::stoll(key)] = player; + } + } + } + + void PlayerDatabase::Save() + { + // TODO: save in thread pool + json data; + + for (auto& [rid, player] : m_Data) + { + data[std::to_string(rid)] = player; + } + + std::ofstream fileStream(m_File); + if (fileStream.is_open()) + { + fileStream << std::setw(4) << data << std::endl; + fileStream.close(); + } + else + LOG(WARNING) << "Unable to save Player Database!"; + } + + std::shared_ptr PlayerDatabase::GetPlayer(uint64_t rid) + { + auto it = m_Data.find(rid); + if (it != m_Data.end()) + { + return it->second; + } + + return nullptr; + } + + void PlayerDatabase::AddPlayer(uint64_t rid, std::string name) + { + if (GetPlayer(rid) == nullptr) + { + auto player = std::make_shared(); + player->rid = rid; + player->name = name; + m_Data[rid] = player; + Save(); + } + } + + std::shared_ptr PlayerDatabase::GetOrCreatePlayer(uint64_t rid, std::string name) + { + auto player = GetPlayer(rid); + if (!player) + { + player = std::make_shared(); + player->rid = rid; + player->name = name; + m_Data[rid] = player; + Save(); + } + return player; + } + + std::unordered_map>& PlayerDatabase::GetAllPlayers() + { + return m_Data; + } + + void PlayerDatabase::SetSelected(std::shared_ptr player) + { + m_Selected = player; + } + + std::shared_ptr PlayerDatabase::GetSelected() + { + return m_Selected; + } + + std::string PlayerDatabase::ConvertDetectionToDescription(Detection infraction) + { + if (auto it = g_DetectionDescs.find(infraction); it != g_DetectionDescs.end()) + return it->second; + return ""; + } + + void PlayerDatabase::AddDetection(std::shared_ptr player, Detection infraction) + { + if (!player->trust) + { + player->infractions.insert((int)infraction); + if (!player->is_modder) + { + player->is_modder = true; + } + Save(); + } + } + + void PlayerDatabase::RemoveRID(uint64_t rockstar_id) + { + if (m_Selected && m_Selected->rid == rockstar_id) + { + m_Selected = nullptr; + } + + if (auto it = m_Data.find(rockstar_id); it != m_Data.end()) + { + m_Data.erase(it); + Save(); + } + } +} \ No newline at end of file diff --git a/src/game/backend/PlayerDatabase.hpp b/src/game/backend/PlayerDatabase.hpp new file mode 100644 index 00000000..ff4af842 --- /dev/null +++ b/src/game/backend/PlayerDatabase.hpp @@ -0,0 +1,76 @@ +#pragma once +#include "core/filemgr/File.hpp" +#include "core/filemgr/FileMgr.hpp" +#include "game/rdr/Player.hpp" + +#include +#include +#include +#include +#include + + +namespace nlohmann +{ + template + struct adl_serializer> + { + static void to_json(json& j, const std::shared_ptr& value) + { + j = *value; + } + + static void from_json(const json& j, std::shared_ptr& value) + { + value = std::make_shared(); + *value = j.get(); + } + }; +} + +namespace YimMenu +{ + enum class Detection : uint32_t; + struct persistent_player; + + class PlayerDatabase + { + private: + std::filesystem::path m_File; + std::unordered_map> m_Data; + std::shared_ptr m_Selected = nullptr; + + public: + PlayerDatabase(); + ~PlayerDatabase(); + + void Load(); + void Save(); + + std::shared_ptr GetPlayer(uint64_t rid); + void AddPlayer(uint64_t rid, std::string name); + std::shared_ptr GetOrCreatePlayer(uint64_t rid, std::string name = "Unknown Player"); + std::unordered_map>& GetAllPlayers(); + void SetSelected(std::shared_ptr player); + std::shared_ptr GetSelected(); + std::string ConvertDetectionToDescription(Detection infraction); + void AddDetection(std::shared_ptr player, Detection infraction); + void RemoveRID(uint64_t rockstar_id); + }; + + struct persistent_player + { + uint64_t rid; + std::string name; + bool is_modder = false; + bool is_admin = false; + bool block_join = false; + bool trust = false; + std::unordered_set infractions; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, rid, name, is_modder, is_admin, block_join, trust, infractions); + }; + + + inline PlayerDatabase* g_PlayerDatabase; // TODO: REMOVE THIS!!!!!! +} \ No newline at end of file diff --git a/src/game/backend/Players.cpp b/src/game/backend/Players.cpp index a8ea730b..fb36be63 100644 --- a/src/game/backend/Players.cpp +++ b/src/game/backend/Players.cpp @@ -2,6 +2,7 @@ #include "game/features/Features.hpp" #include "game/pointers/Pointers.hpp" +#include "PlayerDatabase.hpp" #include #include @@ -21,17 +22,43 @@ namespace YimMenu if (const auto& netPlayer = playerMgr->m_PlayerList[idx]; netPlayer && (Pointers.GetNetPlayerFromPid(idx) == netPlayer) && netPlayer->IsValid()) { - m_Players[idx] = Player(idx); - if (!m_PlayerDatas.contains(idx)) - m_PlayerDatas[idx] = PlayerData(); + OnPlayerJoin(netPlayer); } } } void Players::OnPlayerJoinImpl(CNetGamePlayer* player) { - m_Players[player->m_PlayerIndex] = Player(player); + auto new_player = Player(player); + + m_Players[player->m_PlayerIndex] = new_player; m_PlayerDatas[player->m_PlayerIndex] = PlayerData(); + + if (auto p = g_PlayerDatabase->GetPlayer(new_player.GetRID())) + { + m_PlayerDatas[player->m_PlayerIndex].m_Detections = *reinterpret_cast*>(&p->infractions); + if (p->name != player->GetName()) + { + p->name = player->GetName(); + g_PlayerDatabase->Save(); + } + } + + if (new_player.GetGamerInfo()->m_GamerHandle2 != new_player.GetGamerInfo()->m_GamerHandle) + { + new_player.AddDetection(Detection::SPOOFING_ROCKSTAR_ID); + } + + if (new_player.GetGamerInfo()->m_ExternalAddress.m_packed != new_player.GetExternalAddress().m_packed) + { + new_player.AddDetection(Detection::SPOOFING_IP); + } + + // TODO: needs more work + if (std::string(new_player.GetName()).contains('~')) + { + new_player.AddDetection(Detection::SPOOFING_NAME); + } } void Players::OnPlayerLeaveImpl(CNetGamePlayer* player) @@ -65,4 +92,17 @@ namespace YimMenu return nullptr; } + + Player Players::GetByMessageIdImpl(int id) + { + for (auto& [idx, player] : Players::GetPlayers()) + { + if (player.GetHandle()->m_MessageId == id) + { + return player; + } + } + + return nullptr; + } } \ No newline at end of file diff --git a/src/game/backend/Players.hpp b/src/game/backend/Players.hpp index ab7ed171..f21dac1e 100644 --- a/src/game/backend/Players.hpp +++ b/src/game/backend/Players.hpp @@ -46,6 +46,11 @@ namespace YimMenu return GetInstance().GetByHostTokenImpl(token); } + static Player GetByMessageId(int id) + { + return GetInstance().GetByMessageIdImpl(id); + } + static PlayerData& GetPlayerData(uint8_t idx) { return GetInstance().m_PlayerDatas[idx]; @@ -78,5 +83,6 @@ namespace YimMenu void OnPlayerLeaveImpl(CNetGamePlayer* player); Player GetByRIDImpl(uint64_t rid); Player GetByHostTokenImpl(uint64_t token); + Player GetByMessageIdImpl(int id); }; } \ No newline at end of file diff --git a/src/game/backend/SavedLocations.cpp b/src/game/backend/SavedLocations.cpp new file mode 100644 index 00000000..57c02f0a --- /dev/null +++ b/src/game/backend/SavedLocations.cpp @@ -0,0 +1,112 @@ +#include "SavedLocations.hpp" +#include "core/filemgr/FileMgr.hpp" +#include "core/frontend/Notifications.hpp" + +namespace YimMenu +{ + std::filesystem::path SavedLocations::GetSavedLocationsFilePath() + { + return FileMgr::GetProjectFile("./telelocations.json").Path(); + } + + std::vector SavedLocations::SavedLocationsFilteredListImpl(std::string filter) + { + std::vector filterList{}; + + static auto toLower = [=](std::string text) -> std::string { + std::transform(text.begin(), text.end(), text.begin(), ::tolower); + return text; + }; + + for (auto& location : m_AllSavedLocations | std::views::values | std::views::join) + if (toLower(location.name).find(toLower(filter)) != std::string::npos) + filterList.push_back(location); + + return filterList; + } + + bool SavedLocations::FetchSavedLocationsImpl() + { + m_AllSavedLocations.clear(); + + auto path = GetSavedLocationsFilePath(); + std::ifstream file(path, std::ios::binary); + + try + { + if (!file.is_open()) + return false; + + nlohmann::json j; + file >> j; + m_AllSavedLocations = j.get>>(); + + return true; + } + catch (const std::exception& e) + { + LOG(WARNING) << "Failed fetching saved locations: " << e.what() << '\n'; + return false; + } + + return false; + } + + bool SavedLocations::SaveNewLocationImpl(const std::string& category, SavedLocation t) + { + const auto& pair = m_AllSavedLocations.insert({category, {t}}); + if (!pair.second) + { + pair.first->second.push_back(t); + } + + auto path = GetSavedLocationsFilePath(); + + std::ofstream fileOut(path, std::ofstream::trunc | std::ofstream::binary); + if (!fileOut.is_open()) + return false; + + nlohmann::json j = m_AllSavedLocations; + fileOut << j.dump(4); + fileOut.close(); + + return true; + } + + bool SavedLocations::DeleteSavedLocationImpl(const std::string& category, const std::string& locationName) + { + auto path = GetSavedLocationsFilePath(); + + const auto& it = m_AllSavedLocations.find(category); + if (it == m_AllSavedLocations.end()) + return false; + + std::erase_if(it->second, [locationName](SavedLocation t) { + return t.name == locationName; + }); + + if (!it->second.size()) + { + m_AllSavedLocations.erase(category); + } + + std::ofstream fileOut(path, std::ofstream::trunc | std::ofstream::binary); + if (!fileOut.is_open()) + return false; + + nlohmann::json j = m_AllSavedLocations; + fileOut << j.dump(4); + fileOut.close(); + + return true; + } + + SavedLocation* SavedLocations::GetSavedLocationByNameImpl(std::string name) + { + for (auto& loc : SavedLocationsFilteredList()) + if (loc.name == name) + return &loc; + + return nullptr; + } +} diff --git a/src/game/backend/SavedLocations.hpp b/src/game/backend/SavedLocations.hpp new file mode 100644 index 00000000..9f8de758 --- /dev/null +++ b/src/game/backend/SavedLocations.hpp @@ -0,0 +1,66 @@ +#pragma once +#include "util/teleport.hpp" + +namespace YimMenu +{ + struct SavedLocation + { + std::string name; + float x, y, z; + float yaw = 0.0f, pitch = 0.0f, roll = 0.0f; + }; + + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(SavedLocation, name, x, y, z, yaw, pitch, roll); + + class SavedLocations + { + private: + std::filesystem::path GetSavedLocationsFilePath(); + std::map> m_AllSavedLocations; + + private: + bool FetchSavedLocationsImpl(); + bool SaveNewLocationImpl(const std::string& category, SavedLocation t); + bool DeleteSavedLocationImpl(const std::string& category, const std::string& location_name); + SavedLocation* GetSavedLocationByNameImpl(std::string); + std::vector SavedLocationsFilteredListImpl(std::string filter = ""); + + static SavedLocations& GetInstance() + { + static SavedLocations instance{}; + return instance; + } + + public: + static std::map>& GetAllSavedLocations() + { + return GetInstance().m_AllSavedLocations; + } + + static bool FetchSavedLocations() + { + return GetInstance().FetchSavedLocationsImpl(); + }; + + static bool SaveNewLocation(const std::string& category, SavedLocation t) + { + return GetInstance().SaveNewLocationImpl(category, t); + }; + + static bool DeleteSavedLocation(const std::string& category, const std::string& location_name) + { + return GetInstance().DeleteSavedLocationImpl(category, location_name); + }; + + static SavedLocation* GetSavedLocationByName(std::string location_name) + { + return GetInstance().GetSavedLocationByNameImpl(location_name); + }; + + static std::vector SavedLocationsFilteredList(std::string filter = "") + { + return GetInstance().SavedLocationsFilteredListImpl(filter); + }; + }; + +} \ No newline at end of file diff --git a/src/game/features/network/JoinNewSession.cpp b/src/game/features/network/JoinNewSession.cpp new file mode 100644 index 00000000..919b8fc7 --- /dev/null +++ b/src/game/features/network/JoinNewSession.cpp @@ -0,0 +1,41 @@ +#include "core/commands/Command.hpp" +#include "core/commands/BoolCommand.hpp" +#include "core/commands/Vector3Command.hpp" +#include "game/pointers/Pointers.hpp" +#include "game/backend/ScriptMgr.hpp" +#include "game/rdr/Natives.hpp" + +#include + +namespace YimMenu::Features +{ + static Vector3Command _MatchmakingPosition{"newsessionpos", "Matchmaking Position", "Game position to matchmake around"}; + static BoolCommand _JoinRandomPosse{"newsessionposse", "Join Random Posse", "Automatically join a random open posse when entering a new session"}; + + class JoinNewSession : public Command + { + using Command::Command; + + virtual void OnCall() override + { + int flags = 0; + auto pos = _MatchmakingPosition.GetState(); + + if (_JoinRandomPosse.GetState()) + flags |= 32; + + char id[36]{}; + Pointers.RequestSessionSeamless(*Pointers.ScSession, (rage::rlScSessionId*)&id, flags, &pos, 0); + + while (NETWORK::NETWORK_SESSION_IS_REQUEST_IN_PROGRESS(&id)) + { + if (NETWORK::NETWORK_SESSION_IS_REQUEST_PENDING_TRANSITION(&id)) + NETWORK::_NETWORK_SESSION_TRANSITION_TO_SESSION(&id); + + ScriptMgr::Yield(); + } + } + }; + + static JoinNewSession _JoinNewSession{"newsession", "Join New Session", "Seamlessly joins a new session"}; +} \ No newline at end of file diff --git a/src/game/features/players/teleport/TpPlayerToMadamNazar.cpp b/src/game/features/players/teleport/TpPlayerToMadamNazar.cpp new file mode 100644 index 00000000..4d9bc1ac --- /dev/null +++ b/src/game/features/players/teleport/TpPlayerToMadamNazar.cpp @@ -0,0 +1,24 @@ +#include "game/commands/PlayerCommand.hpp" +#include "core/frontend/Notifications.hpp" +#include "game/backend/Self.hpp" +#include "game/rdr/Natives.hpp" +#include "game/rdr/ScriptGlobal.hpp" +#include "util/Teleport.hpp" + +namespace YimMenu::Features +{ + class TpPlayerToMadamNazar : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + // search for "MPSW_LOCATION_00" in long_update + static constexpr auto NazarLocation = ScriptGlobal(1051832).At(4681); + + virtual void OnCall(Player player) override + { + if (NazarLocation.CanAccess()) + Teleport::TeleportPlayerToCoords(player, *NazarLocation.As()); + } + }; + + static TpPlayerToMadamNazar _TpPlayerToMadamNazar{"tpplayertomadamnazar", "Teleport To Madam Nazar", "Teleports the player to Madam Nazar's current location"}; +} diff --git a/src/game/features/players/toxic/Circus.cpp b/src/game/features/players/toxic/Circus.cpp index 383b6853..ae50c3c1 100644 --- a/src/game/features/players/toxic/Circus.cpp +++ b/src/game/features/players/toxic/Circus.cpp @@ -1,7 +1,6 @@ #include "game/commands/PlayerCommand.hpp" #include "game/backend/Self.hpp" -#include "game/rdr/Natives.hpp" -#include "util/VehicleSpawner.hpp" +#include "game/rdr/Vehicle.hpp" namespace YimMenu::Features @@ -12,9 +11,9 @@ namespace YimMenu::Features virtual void OnCall(Player player) override { - float rot = ENTITY::GET_ENTITY_ROTATION(player.GetPed().GetHandle(), 0).z; - Vector3 coords = ENTITY::GET_ENTITY_COORDS(player.GetPed().GetHandle(), true, true); - SpawnVehicle("wagonCircus01x", coords, rot); + float rot = player.GetPed().GetRotation(0).z; + auto coords = player.GetPed().GetPosition(); + Vehicle::Create("wagonCircus01x"_J, coords, rot); } }; diff --git a/src/game/features/players/toxic/RemoteBolas.cpp b/src/game/features/players/toxic/RemoteBolas.cpp new file mode 100644 index 00000000..5b9d5c60 --- /dev/null +++ b/src/game/features/players/toxic/RemoteBolas.cpp @@ -0,0 +1,56 @@ +#include "core/frontend/Notifications.hpp" +#include "game/commands/PlayerCommand.hpp" +#include "game/rdr/Enums.hpp" +#include "game/rdr/Natives.hpp" +#include "game/rdr/Ped.hpp" + + +namespace YimMenu::Features +{ + + class RemoteBolas : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + + virtual void OnCall(Player player) override + { + bool canUseBolas = PED::_GET_PED_LASSO_HOGTIE_FLAG(player.GetPed().GetHandle(), (int)LassoFlags::LHF_CAN_BE_LASSOED) + && !PED::_GET_PED_LASSO_HOGTIE_FLAG(player.GetPed().GetHandle(), (int)LassoFlags::LHF_DISABLE_IN_MP); + if (canUseBolas) + { + auto striker = Ped::Create("cs_brendacrawley"_J, + player.GetPed().GetPosition() - Vector3(5, 0, 0), + player.GetPed().GetRotation().z); + + striker.SetVisible(false); + + const auto strikerPos = striker.GetPosition(); + const auto targetPos = player.GetPed().GetPosition(); + + MISC::SHOOT_SINGLE_BULLET_BETWEEN_COORDS(strikerPos.x, + strikerPos.y, + strikerPos.z, + targetPos.x, + targetPos.y, + targetPos.z, + 0, + true, + "weapon_thrown_bolas_ironspiked"_J, + striker.GetHandle(), + false, + false, + 100.f, + true); + + striker.ForceControl(); + striker.Delete(); + } + else + { + Notifications::Show("Remote Bolas", "This player has bolas protections enabled!", NotificationType::Error); + } + } + }; + + static RemoteBolas _RemoteBolas{"remotebolas", "Remote Bolas", "Remotely strike the player with bolas"}; +} \ No newline at end of file diff --git a/src/game/features/players/toxic/SendStableEvent.cpp b/src/game/features/players/toxic/SendStableEvent.cpp index e9d205cc..9aa7ea5f 100644 --- a/src/game/features/players/toxic/SendStableEvent.cpp +++ b/src/game/features/players/toxic/SendStableEvent.cpp @@ -21,7 +21,7 @@ namespace YimMenu::Features data[2] = NETWORK::GET_NETWORK_TIME_ACCURATE(); data[4] = _StableMountEvent.GetState(); data[5] = _MountInstance.GetState(); - + Scripts::SendScriptEvent(data, 6, 0, 1 << player.GetId()); } diff --git a/src/game/features/self/Freecam.cpp b/src/game/features/self/Freecam.cpp new file mode 100644 index 00000000..5697da69 --- /dev/null +++ b/src/game/features/self/Freecam.cpp @@ -0,0 +1,145 @@ +#include "core/commands/LoopedCommand.hpp" +#include "game/backend/Self.hpp" +#include "game/frontend/GUI.hpp" +#include "game/rdr/Enums.hpp" +#include "game/rdr/Natives.hpp" +#include "util/Math.hpp" +#include "util/teleport.hpp" + + +namespace YimMenu::Features +{ + class Freecam : public LoopedCommand + { + using LoopedCommand::LoopedCommand; + + static inline int camEntity = 0; + static inline Vector3 position{}; + static inline Vector3 rotation{}; + + void CreateFreecam() + { + if (camEntity) + return; + + camEntity = CAM::CREATE_CAM("DEFAULT_SCRIPTED_CAMERA", 0); + position = CAM::GET_GAMEPLAY_CAM_COORD(); + rotation = CAM::GET_GAMEPLAY_CAM_ROT(2); + + CAM::SET_CAM_COORD(camEntity, position.x, position.y, position.z); + CAM::SET_CAM_ROT(camEntity, rotation.x, rotation.y, rotation.z, 2); + CAM::SET_CAM_ACTIVE(camEntity, true); + CAM::RENDER_SCRIPT_CAMS(true, true, 500, true, true, 0); + } + + void UpdateFreecamPosition() + { + if (GUI::IsOpen()) + return; + Vector3 PosChange{}; + static float speed = 0.5f; + static float accel = 0.0f; + + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (Hash)NativeInputs::INPUT_JUMP)) + { + PosChange.z += speed / 2; + } // Left Shift + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)NativeInputs::INPUT_DUCK) || PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)NativeInputs::INPUT_HORSE_STOP)) + { + PosChange.z -= speed / 2; + } // Left Control + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (Hash)NativeInputs::INPUT_MOVE_UP_ONLY)) + { + PosChange.y += speed; + } // Forward + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (Hash)NativeInputs::INPUT_MOVE_DOWN_ONLY)) + { + PosChange.y -= speed; + } // Backward + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (Hash)NativeInputs::INPUT_MOVE_LEFT_ONLY)) + { + PosChange.x -= speed; + } // Left + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (Hash)NativeInputs::INPUT_MOVE_RIGHT_ONLY)) + { + PosChange.x += speed; + } // Right + + + if (PosChange.x == 0.0f && PosChange.y == 0.0f && PosChange.z == 0.0f) + { + accel = 0.0f; + } + else if (accel < 10) + { + accel += 0.15f; + } + + Vector3 rot = CAM::GET_CAM_ROT(camEntity, 2); + float yaw = Math::DegToRad(rot.z); + + position.x += (PosChange.x * cos(yaw) - PosChange.y * sin(yaw)) * accel; + position.y += (PosChange.x * sin(yaw) + PosChange.y * cos(yaw)) * accel; + position.z += PosChange.z * accel; + + CAM::SET_CAM_COORD(camEntity, position.x, position.y, position.z); + STREAMING::SET_FOCUS_POS_AND_VEL(position.x, position.y, position.z, 0.0f, 0.0f, 0.0f); + } + + virtual void OnTick() override + { + CreateFreecam(); + UpdateFreecamPosition(); + + rotation = CAM::GET_GAMEPLAY_CAM_ROT(2); + CAM::SET_CAM_ROT(camEntity, rotation.x, rotation.y, rotation.z, 2); + + TASK::CLEAR_PED_TASKS(Self::GetPed().GetHandle(), false, true); + TASK::CLEAR_PED_SECONDARY_TASK(Self::GetPed().GetHandle()); + TASK::CLEAR_PED_TASKS_IMMEDIATELY(Self::GetPed().GetHandle(), true, true); + Self::GetPed().SetFrozen(true); + Self::GetPed().SetVisible(false); + + if (!GUI::IsOpen()) + { + static Hash controls[]{ + (Hash)NativeInputs::INPUT_LOOK_LR, + (Hash)NativeInputs::INPUT_LOOK_UD, + (Hash)NativeInputs::INPUT_LOOK_UP_ONLY, + (Hash)NativeInputs::INPUT_LOOK_DOWN_ONLY, + (Hash)NativeInputs::INPUT_LOOK_LEFT_ONLY, + (Hash)NativeInputs::INPUT_LOOK_RIGHT_ONLY, + }; + PAD::DISABLE_ALL_CONTROL_ACTIONS(0); + + for (Hash c : controls) + { + PAD::ENABLE_CONTROL_ACTION(0, c, true); + } + + if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (Hash)NativeInputs::INPUT_FRONTEND_ACCEPT)) + { + Teleport::TeleportPlayerToCoords(Self::GetPlayer(), position); + } + } + } + + virtual void OnDisable() override + { + if (!camEntity) + return; + + CAM::SET_CAM_ACTIVE(camEntity, false); + CAM::RENDER_SCRIPT_CAMS(false, true, 500, true, true, 0); + CAM::DESTROY_CAM(camEntity, false); + STREAMING::CLEAR_FOCUS(); + + Self::GetPed().SetFrozen(false); + Self::GetPed().SetVisible(true); + + camEntity = 0; + } + }; + + static Freecam _Freecam{"freecam", "Freecam", "Detaches your camera and allows you to go anywhere!"}; +} diff --git a/src/game/features/system/Chat.cpp b/src/game/features/system/Chat.cpp index 792e21e9..1b23f7ed 100644 --- a/src/game/features/system/Chat.cpp +++ b/src/game/features/system/Chat.cpp @@ -18,7 +18,7 @@ namespace YimMenu::Features virtual void OnCall() override { - if (*Pointers.IsSessionStarted && !SCRIPTS::IS_LOADING_SCREEN_VISIBLE() && MISC::UPDATE_ONSCREEN_KEYBOARD() != 0 && !GUI::IsOpen() && !HUD::IS_PAUSE_MENU_ACTIVE()) + if (*Pointers.IsSessionStarted && !SCRIPTS::IS_LOADING_SCREEN_VISIBLE() && MISC::UPDATE_ONSCREEN_KEYBOARD() != 0 && !GUI::IsOpen()) { ScriptMgr::Yield(100ms); // Delay so hotkey key doesn't get mistaken as input bool isChatCancelled = false; diff --git a/src/game/features/world/Bring.cpp b/src/game/features/world/Bring.cpp new file mode 100644 index 00000000..492ab8a0 --- /dev/null +++ b/src/game/features/world/Bring.cpp @@ -0,0 +1,61 @@ +#include "core/commands/Command.hpp" +#include "game/backend/Self.hpp" +#include "game/rdr/Pools.hpp" + +namespace YimMenu::Features +{ + class BringAllObjs : public Command + { + using Command::Command; + + virtual void OnCall() override + { + auto pos = Self::GetPed().GetPosition(); + for (auto obj : Pools::GetObjects()) + { + if (obj) + { + obj.ForceControl(); + obj.SetPosition(pos); + } + } + } + }; + + class BringAllPeds : public Command + { + using Command::Command; + + virtual void OnCall() override + { + auto pos = Self::GetPed().GetPosition(); + for (auto ped : Pools::GetPeds()) + { + if (!ped.IsPlayer()) + { + ped.ForceControl(); + ped.SetPosition(pos); + } + } + } + }; + + class BringAllVehs : public Command + { + using Command::Command; + + virtual void OnCall() override + { + auto pos = Self::GetPed().GetPosition(); + for (auto veh : Pools::GetVehicles()) + { + veh.ForceControl(); + veh.SetPosition(pos); + } + } + }; + + static BringAllObjs _BringAllObjs{"bringobjs", "Bring All Objects", "Teleports all game objects to you"}; + static BringAllPeds _BringAllPeds{"bringpeds", "Bring All Peds", "Teleports all game peds to you"}; + static BringAllVehs _BringAllVehs{"bringvehs", "Bring All Vehicles", "Teleports all game vehicles to you"}; +} \ No newline at end of file diff --git a/src/game/features/world/Delete.cpp b/src/game/features/world/Delete.cpp new file mode 100644 index 00000000..7af56312 --- /dev/null +++ b/src/game/features/world/Delete.cpp @@ -0,0 +1,50 @@ +#include "core/commands/Command.hpp" +#include "game/rdr/Pools.hpp" + +namespace YimMenu::Features +{ + class DeleteAllObjects : public Command + { + using Command::Command; + + virtual void OnCall() override + { + for (auto obj : Pools::GetObjects()) + { + if (obj) + obj.Delete(); + } + } + }; + + class DeleteAllPeds : public Command + { + using Command::Command; + + virtual void OnCall() override + { + for (auto ped : Pools::GetPeds()) + { + if (!ped.IsPlayer()) + ped.Delete(); + } + } + }; + + class DeleteAllVehs : public Command + { + using Command::Command; + + virtual void OnCall() override + { + for (auto veh : Pools::GetVehicles()) + { + veh.Delete(); + } + } + }; + + static DeleteAllObjects _DeleteAllObjects{"delobjs", "Delete All Objects", "Deletes all objects in the game world, including mission critical objects"}; + static DeleteAllPeds _DeleteAllPeds{"delpeds", "Delete All Peds", "Deletes all peds in the game world, including mission critical peds"}; + static DeleteAllVehs _DeleteAllVehs{"delvehs", "Delete All Vehicles", "Deletes all vehicles in the game world, including mission critical vehicles"}; +} \ No newline at end of file diff --git a/src/game/frontend/ContextMenu.cpp b/src/game/frontend/ContextMenu.cpp index ce107a7b..b2dffbb4 100644 --- a/src/game/frontend/ContextMenu.cpp +++ b/src/game/frontend/ContextMenu.cpp @@ -12,6 +12,10 @@ namespace YimMenu::Features { BoolCommand _ContextMenu("ctxmenu", "Context Menu", "Enables a context menu that allows you to perform actions on nearby entities and players"); + BoolCommand _ContextPlayers("ctxmenuplayers", "Show Players", "Should the context menu show players?"); + BoolCommand _ContextPeds("ctxmenupeds", "Show Peds", "Should the context menu show peds?"); + BoolCommand _ContextVehicles("ctxmenuvehicles", "Show Vehicles", "Should the context menu show vehicles?"); + BoolCommand _ContextObjects("ctxmenuobjects", "Show Objects", "Should the context menu show objects?"); } namespace YimMenu @@ -21,7 +25,8 @@ namespace YimMenu return std::abs(screenPos.x - 0.5) + std::abs(screenPos.y - 0.5); } - inline int GetEntityHandleClosestToMiddleOfScreen(bool includePlayers, bool includePeds, bool includeVehicles = false, bool includeObjects = false) + // TODO: Refactor this - LOS check + inline int GetEntityHandleClosestToMiddleOfScreen(bool includePlayers, bool includePeds, bool includeVehicles, bool includeObjects) { int closestHandle{}; float distance = 1; @@ -31,7 +36,7 @@ namespace YimMenu rage::fvector2 screenPos{}; float worldCoords_[3] = {worldCoords.x, worldCoords.y, worldCoords.z}; Pointers.WorldToScreen(worldCoords_, &screenPos.x, &screenPos.y); - if (CumulativeDistanceToMiddleOfScreen(screenPos) < distance && handle != Self::GetPed().GetHandle()) + if (CumulativeDistanceToMiddleOfScreen(screenPos) < distance && handle != Self::GetPed().GetHandle()) { closestHandle = handle; distance = CumulativeDistanceToMiddleOfScreen(screenPos); @@ -56,6 +61,24 @@ namespace YimMenu } } + if (includeVehicles) + { + for (Entity obj : Pools::GetObjects()) + { + if (obj.IsValid() || obj.GetPointer()) + updateClosestEntity(obj.GetHandle()); + } + } + + if (includeObjects) + { + for (Entity veh : Pools::GetVehicles()) + { + if (veh.IsValid() || veh.GetPointer()) + updateClosestEntity(veh.GetHandle()); + } + } + return closestHandle; } @@ -69,7 +92,11 @@ namespace YimMenu if (m_Enabled) { - auto handle = GetEntityHandleClosestToMiddleOfScreen(true, true); + auto handle = GetEntityHandleClosestToMiddleOfScreen( + Features::_ContextPlayers.GetState(), + Features::_ContextPeds.GetState(), + Features::_ContextVehicles.GetState(), + Features::_ContextObjects.GetState()); static auto switchToMenu = [&](ContextOperationsMenu menu) -> void { if (m_CurrentOperationsMenu != menu) @@ -78,7 +105,7 @@ namespace YimMenu } }; - if (handle && ENTITY::DOES_ENTITY_EXIST(handle)) + if (handle && ENTITY::DOES_ENTITY_EXIST(handle) && ENTITY::HAS_ENTITY_CLEAR_LOS_TO_ENTITY(Self::GetPed().GetHandle(), handle, 17)) { m_Entity = handle; @@ -91,11 +118,11 @@ namespace YimMenu } else if (m_Entity.IsVehicle()) { - switchToMenu(ContextMenuDefault); // TODO: Create Vehicle menu + switchToMenu(ContextMenuVehicles); // TODO: Create Vehicle menu } else if (m_Entity.IsObject()) { - switchToMenu(ContextMenuDefault); // TODO: Create Object menu + switchToMenu(ContextMenuObjects); // TODO: Create Object menu } if (m_CurrentOperationsMenu.m_SelectedOperation.m_Name.empty()) diff --git a/src/game/frontend/ContextMenus.hpp b/src/game/frontend/ContextMenus.hpp index 1f086a35..22bdda47 100644 --- a/src/game/frontend/ContextMenus.hpp +++ b/src/game/frontend/ContextMenus.hpp @@ -2,8 +2,8 @@ #include "ContextMenu.hpp" #include "core/commands/Commands.hpp" #include "game/backend/Players.hpp" -#include "game/commands/PlayerCommand.hpp" #include "game/backend/Self.hpp" +#include "game/commands/PlayerCommand.hpp" #include "game/rdr/Enums.hpp" #include "game/rdr/Natives.hpp" #include "util/teleport.hpp" @@ -11,7 +11,8 @@ namespace YimMenu { - inline ContextOperationsMenu ContextMenuDefault = ContextOperationsMenu("Default", {ContextMenuOperation{"Error", [&](Entity) {}}}); + inline ContextOperationsMenu ContextMenuDefault = ContextOperationsMenu("Default", {ContextMenuOperation{"Error", [&](Entity) { + }}}); inline ContextOperationsMenu ContextMenuPlayers = ContextOperationsMenu("Players", { @@ -70,6 +71,66 @@ namespace YimMenu [&](Entity entity) { Hash modelHash = ENTITY::GET_ENTITY_MODEL(entity.GetHandle()); + ImGui::SetClipboardText(std::format("0x{:08X}", (joaat_t)modelHash).c_str()); + LOG(INFO) << std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(); + Notifications::Show("Context Menu", std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(), NotificationType::Info); + }}, + }); + + inline ContextOperationsMenu ContextMenuVehicles = ContextOperationsMenu("Vehicles", + { + ContextMenuOperation{"Explode", + [&](Entity entity) { + auto pedCoords = ENTITY::GET_ENTITY_COORDS(entity.GetHandle(), true, true); + FIRE::ADD_EXPLOSION(pedCoords.x, pedCoords.y, pedCoords.z, (int)ExplosionTypes::UNK, 10.0f, true, false, 1.0f); + }}, + {"Apply Force", + [&](Entity entity) { + auto currentCoords = ENTITY::GET_ENTITY_COORDS(entity.GetHandle(), true, true); + ENTITY::APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(entity.GetHandle(), + 1, + currentCoords.x - 3, + currentCoords.y, + currentCoords.z, + true, + false, + true, + false); + }}, + {"Copy Hash", + [&](Entity entity) { + Hash modelHash = ENTITY::GET_ENTITY_MODEL(entity.GetHandle()); + + ImGui::SetClipboardText(std::format("0x{:08X}", (joaat_t)modelHash).c_str()); + LOG(INFO) << std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(); + Notifications::Show("Context Menu", std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(), NotificationType::Info); + }}, + }); + + inline ContextOperationsMenu ContextMenuObjects = ContextOperationsMenu("Objects", + { + ContextMenuOperation{"Explode", + [&](Entity entity) { + auto pedCoords = ENTITY::GET_ENTITY_COORDS(entity.GetHandle(), true, true); + FIRE::ADD_EXPLOSION(pedCoords.x, pedCoords.y, pedCoords.z, (int)ExplosionTypes::UNK, 10.0f, true, false, 1.0f); + }}, + {"Apply Force", + [&](Entity entity) { + auto currentCoords = ENTITY::GET_ENTITY_COORDS(entity.GetHandle(), true, true); + ENTITY::APPLY_FORCE_TO_ENTITY_CENTER_OF_MASS(entity.GetHandle(), + 1, + currentCoords.x - 3, + currentCoords.y, + currentCoords.z, + true, + false, + true, + false); + }}, + {"Copy Hash", + [&](Entity entity) { + Hash modelHash = ENTITY::GET_ENTITY_MODEL(entity.GetHandle()); + ImGui::SetClipboardText(std::format("0x{:08X}", (joaat_t)modelHash).c_str()); LOG(INFO) << std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(); Notifications::Show("Context Menu", std::format("Copied hash 0x{:08X}", (joaat_t)modelHash).c_str(), NotificationType::Info); diff --git a/src/game/frontend/ESP.cpp b/src/game/frontend/ESP.cpp index 0c306576..3e7b96d2 100644 --- a/src/game/frontend/ESP.cpp +++ b/src/game/frontend/ESP.cpp @@ -1,11 +1,11 @@ #include "Esp.hpp" #include "common.hpp" +#include "core/commands/BoolCommand.hpp" #include "game/backend/Players.hpp" #include "game/backend/Self.hpp" #include "game/pointers/Pointers.hpp" #include "util/Math.hpp" -#include "core/commands/BoolCommand.hpp" namespace { @@ -24,7 +24,10 @@ namespace namespace YimMenu::Features { - BoolCommand _ESP("esp", "ESP", "Draws lines to nearby players and shows their skeleton"); + BoolCommand _ESP("esp", "ESP", "Draws player info"); + BoolCommand _ESPName("espname", "Show Name", "Should the ESP draw names?"); + BoolCommand _ESPDistance("espdistance", "Show Distance", "Should the ESP draw distance?"); + BoolCommand _ESPSkeleton("espskeleton", "Show Skeleton", "Should the ESP draw the skeleton?"); } namespace YimMenu @@ -76,11 +79,12 @@ namespace YimMenu //TODO : Very bare bones currently, expand and possibly refactor void ESP::DrawPlayer(Player& plyr, ImDrawList* drawList) { - if (!plyr.IsValid() || !plyr.GetPed().IsValid() || plyr == Self::GetPlayer() || boneToScreen(plyr.GetPed().GetBonePosition(torsoBone)).x == 0) + if (!plyr.IsValid() || !plyr.GetPed().IsValid() || plyr == Self::GetPlayer() + || boneToScreen(plyr.GetPed().GetBonePosition(torsoBone)).x == 0) return; - float distanceToPlayer = Self::GetPed().GetPosition().GetDistance(plyr.GetPed().GetBonePosition(torsoBone)); - int alphaBasedOnDistance = 255; + float distanceToPlayer = Self::GetPed().GetPosition().GetDistance(plyr.GetPed().GetBonePosition(torsoBone)); + int alphaBasedOnDistance = 255; ImColor colorBasedOnDistance = Red; if (distanceToPlayer < 100.f) @@ -94,23 +98,30 @@ namespace YimMenu auto* currentFont = ImGui::GetFont(); currentFont->Scale *= 1.2; ImGui::PushFont(ImGui::GetFont()); - //Name - drawList->AddText(boneToScreen(plyr.GetPed().GetBonePosition(headBone)), plyr == Players::GetSelected() ? Blue : ImColor(255, 255, 255, alphaBasedOnDistance), plyr.GetName()); - //Distance - drawList->AddText({boneToScreen(plyr.GetPed().GetBonePosition(headBone)).x, - boneToScreen(plyr.GetPed().GetBonePosition(headBone)).y + 20}, - colorBasedOnDistance, - std::to_string((int)Self::GetPed().GetPosition().GetDistance(plyr.GetPed().GetBonePosition(torsoBone))) - .data()); + + if (Features::_ESPName.GetState()) + { + drawList->AddText(boneToScreen(plyr.GetPed().GetBonePosition(headBone)), plyr == Players::GetSelected() ? Blue : ImColor(255, 255, 255, alphaBasedOnDistance), plyr.GetName()); + } + + if (Features::_ESPDistance.GetState()) + { + drawList->AddText({boneToScreen(plyr.GetPed().GetBonePosition(headBone)).x, + boneToScreen(plyr.GetPed().GetBonePosition(headBone)).y + 20}, + colorBasedOnDistance, + std::to_string((int)Self::GetPed().GetPosition().GetDistance(plyr.GetPed().GetBonePosition(torsoBone))).data()); + } currentFont->Scale = originalFontSize; ImGui::PopFont(); //TODO Boxes, Distance colors, Friendlies, Tracers, Health bars - //TODO Make this a setting - if (distanceToPlayer < 100.f) - DrawSkeleton(plyr, drawList, ImColor(255, 255, 255, 255)); + if (Features::_ESPSkeleton.GetState()) + { + if (distanceToPlayer < 100.f) + DrawSkeleton(plyr, drawList, ImColor(255, 255, 255, 255)); + } } void ESP::Draw() diff --git a/src/game/frontend/items/CommandItem.cpp b/src/game/frontend/items/CommandItem.cpp index dcfe010e..622f6cd9 100644 --- a/src/game/frontend/items/CommandItem.cpp +++ b/src/game/frontend/items/CommandItem.cpp @@ -5,8 +5,9 @@ namespace YimMenu { - CommandItem::CommandItem(joaat_t id) : - m_Command(Commands::GetCommand(id)) + CommandItem::CommandItem(joaat_t id, std::optional label_override) : + m_Command(Commands::GetCommand(id)), + m_LabelOverride(label_override) { } @@ -18,7 +19,7 @@ namespace YimMenu return; } - if (ImGui::Button(m_Command->GetLabel().data())) + if (ImGui::Button(m_LabelOverride.has_value() ? m_LabelOverride.value().data() : m_Command->GetLabel().data())) { FiberPool::Push([this] { m_Command->Call(); diff --git a/src/game/frontend/items/Items.hpp b/src/game/frontend/items/Items.hpp index b1c8e758..7049323d 100644 --- a/src/game/frontend/items/Items.hpp +++ b/src/game/frontend/items/Items.hpp @@ -9,6 +9,7 @@ namespace YimMenu class ListCommand; class IntCommand; class FloatCommand; + class Vector3Command; class Command; class Button : public UIItem @@ -27,21 +28,23 @@ namespace YimMenu class CommandItem : public UIItem { public: - explicit CommandItem(joaat_t id); + explicit CommandItem(joaat_t id, std::optional label_override = std::nullopt); void Draw() override; private: Command* m_Command; + std::optional m_LabelOverride; }; class PlayerCommandItem : public UIItem { public: - explicit PlayerCommandItem(joaat_t id); + explicit PlayerCommandItem(joaat_t id, std::optional label_override = std::nullopt); void Draw() override; private: PlayerCommand* m_Command; + std::optional m_LabelOverride; }; class BoolCommandItem : public UIItem @@ -77,6 +80,19 @@ namespace YimMenu std::optional m_LabelOverride; }; + class Vector3CommandItem : public UIItem + { + public: + explicit Vector3CommandItem(joaat_t id, std::optional label_override = std::nullopt); + void Draw() override; + + private: + Vector3Command* m_Command; + std::optional m_LabelOverride; + std::string m_CurrentCategory{}; + std::string m_CurrentFilter{}; + }; + class ListCommandItem : public UIItem { public: diff --git a/src/game/frontend/items/PlayerCommandItem.cpp b/src/game/frontend/items/PlayerCommandItem.cpp index 6691d56b..897060ea 100644 --- a/src/game/frontend/items/PlayerCommandItem.cpp +++ b/src/game/frontend/items/PlayerCommandItem.cpp @@ -6,8 +6,9 @@ namespace YimMenu { - PlayerCommandItem::PlayerCommandItem(joaat_t id) : - m_Command(Commands::GetCommand(id)) + PlayerCommandItem::PlayerCommandItem(joaat_t id, std::optional label_override) : + m_Command(Commands::GetCommand(id)), + m_LabelOverride(label_override) { } @@ -19,7 +20,7 @@ namespace YimMenu return; } - if (ImGui::Button(m_Command->GetLabel().data())) + if (ImGui::Button(m_LabelOverride.has_value() ? m_LabelOverride.value().data() : m_Command->GetLabel().data())) { FiberPool::Push([this] { if (Players::GetSelected().IsValid()) diff --git a/src/game/frontend/items/Vector3CommandItem.cpp b/src/game/frontend/items/Vector3CommandItem.cpp new file mode 100644 index 00000000..69abaa83 --- /dev/null +++ b/src/game/frontend/items/Vector3CommandItem.cpp @@ -0,0 +1,120 @@ +#include "Items.hpp" +#include "core/commands/Command.hpp" +#include "core/commands/Commands.hpp" +#include "core/commands/Vector3Command.hpp" +#include "game/backend/SavedLocations.hpp" +#include "game/backend/Self.hpp" + +namespace YimMenu +{ + Vector3CommandItem::Vector3CommandItem(joaat_t id, std::optional label_override) : + m_Command(Commands::GetCommand(id)), + m_LabelOverride(label_override) + { + } + + void Vector3CommandItem::Draw() + { + if (!m_Command) + { + ImGui::Text("Unknown!"); + return; + } + + auto value = m_Command->GetState(); + ImGui::PushID(m_Command); + ImGui::SetNextItemWidth(180); + if (ImGui::InputFloat3("##coord_inp", &value.x, "%.1f")) + m_Command->SetState(value); + if (Self::GetPed()) + { + ImGui::SameLine(); + if (ImGui::Button("Current")) + m_Command->SetState(Self::GetPed().GetPosition()); + } + ImGui::SameLine(); + if (ImGui::Button("Saved...")) + ImGui::OpenPopup("##saved"); + + if (ImGui::BeginPopup("##saved", ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize)) + { + ImGui::Text("Click on a location to select it. Add more at Teleport > Saved"); + InputTextWithHint("##filter", "Search", &m_CurrentFilter).Draw(); + + const float max_length = Pointers.ScreenResY / 3.2; + + // TODO: duplicated code + ImGui::BeginGroup(); + ImGui::Text("Categories"); + + if (ImGui::BeginListBox("##categories", {200, max_length})) + { + for (auto& l : SavedLocations::GetAllSavedLocations() | std::ranges::views::keys) + { + if (ImGui::Selectable(l.data(), l == m_CurrentCategory)) + { + m_CurrentCategory = l; + } + + if (m_CurrentCategory.empty()) + { + m_CurrentCategory = l; + } + } + ImGui::EndListBox(); + } + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Text("Locations"); + if (ImGui::BeginListBox("##saved_locs", {200, max_length})) + { + if (SavedLocations::GetAllSavedLocations().find(m_CurrentCategory) != SavedLocations::GetAllSavedLocations().end()) + { + std::vector current_list{}; + + if (!m_CurrentFilter.empty()) + current_list = SavedLocations::SavedLocationsFilteredList(m_CurrentFilter); + else + current_list = SavedLocations::GetAllSavedLocations().at(m_CurrentCategory); + + for (const auto& l : current_list) + { + if (ImGui::Selectable(l.name.data(), false, ImGuiSelectableFlags_AllowDoubleClick)) + { + m_Command->SetState({l.x, l.y, l.z}); + ImGui::CloseCurrentPopup(); + } + + if (ImGui::IsItemHovered() && l.name.length() > 27) + { + ImGui::BeginTooltip(); + ImGui::Text(l.name.data()); + ImGui::EndTooltip(); + } + } + } + + ImGui::EndListBox(); + } + + ImGui::EndGroup(); + + if (ImGui::Button("Close")) + { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + auto& label = m_LabelOverride.has_value() ? m_LabelOverride.value() : m_Command->GetLabel(); + if (!label.empty()) + { + ImGui::SameLine(); + ImGui::Text(label.c_str()); + } + + ImGui::PopID(); + } +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Network.cpp b/src/game/frontend/submenus/Network.cpp index 01752b47..0696cb8e 100644 --- a/src/game/frontend/submenus/Network.cpp +++ b/src/game/frontend/submenus/Network.cpp @@ -4,7 +4,7 @@ #include "core/commands/HotkeySystem.hpp" #include "core/commands/LoopedCommand.hpp" #include "core/frontend/Notifications.hpp" -#include "core/player_database/PlayerDatabase.hpp" +#include "game/backend/PlayerDatabase.hpp" #include "game/backend/FiberPool.hpp" #include "game/backend/Players.hpp" #include "game/backend/ScriptMgr.hpp" @@ -21,6 +21,7 @@ #include #include #include +#include "Network.hpp" namespace YimMenu::Submenus @@ -62,18 +63,33 @@ namespace YimMenu::Submenus auto session = std::make_shared("Session"); auto spoofing = std::make_shared("Spoofing"); auto database = std::make_shared("Player Database"); + auto sessionSwitcherGroup = std::make_shared("Session Switcher"); + auto teleportGroup = std::make_shared("Teleport"); + auto toxicGroup = std::make_shared("Toxic"); + auto miscGroup = std::make_shared("Misc"); auto nameChangerGroup = std::make_shared("Name Changer"); auto blipSpoofingGroup = std::make_shared("Blip Spoofing"); + auto sessionSpoofingGroup = std::make_shared("Session Spoofing"); + + sessionSwitcherGroup->AddItem(std::make_shared("newsessionpos"_J)); + sessionSwitcherGroup->AddItem(std::make_shared("newsessionposse"_J)); + sessionSwitcherGroup->AddItem(std::make_shared("newsession"_J)); + + teleportGroup->AddItem(std::make_shared("bringall"_J, "Bring All")); + teleportGroup->AddItem(std::make_shared("tpalltowaypoint"_J)); + teleportGroup->AddItem(std::make_shared("tpalltojail"_J)); - session->AddItem(std::make_shared("revealall"_J)); - session->AddItem(std::make_shared("explodeall"_J)); - session->AddItem(std::make_shared("maxhonorall"_J)); - session->AddItem(std::make_shared("minhonorall"_J)); - session->AddItem(std::make_shared("bringall"_J)); - session->AddItem(std::make_shared("tpalltowaypoint"_J)); - session->AddItem(std::make_shared("tpalltojail"_J)); + toxicGroup->AddItem(std::make_shared("explodeall"_J)); + toxicGroup->AddItem(std::make_shared("maxhonorall"_J)); + toxicGroup->AddItem(std::make_shared("minhonorall"_J)); - session->AddItem(std::make_shared("blockalltelemetry"_J)); + miscGroup->AddItem(std::make_shared("revealall"_J)); + miscGroup->AddItem(std::make_shared("blockalltelemetry"_J)); + + session->AddItem(sessionSwitcherGroup); + session->AddItem(teleportGroup); + session->AddItem(toxicGroup); + session->AddItem(miscGroup); spoofing->AddItem(std::make_shared("hidegod"_J)); spoofing->AddItem(std::make_shared("voicechatoverride"_J)); @@ -137,7 +153,7 @@ namespace YimMenu::Submenus for (const auto& pair : count_map) { // TODO: find a better way to do this - ImGui::BulletText(std::string(g_PlayerDatabase->ConvertInfractionToDescription(pair.first)) + ImGui::BulletText(std::string(g_PlayerDatabase->ConvertDetectionToDescription(Detection(pair.first))) .append(" - ") .append("x") .append(std::to_string(pair.second)) @@ -145,6 +161,21 @@ namespace YimMenu::Submenus } } + if (ImGui::Button("Join Player")) + { + FiberPool::Push([] { + using gp = void*(*)(); + using join = void(*)(void*, rage::rlGamerHandle*, int); + + gp g = (gp)((__int64)GetModuleHandleA(0) + 0x22b9800); + join j = (join)((__int64)GetModuleHandleA(0) + 0x22d7080); + + rage::rlGamerHandle hnd(current_player->rid); + + j(g(), &hnd, 512); + }); + } + if (ImGui::Button("Delete Player")) { g_PlayerDatabase->RemoveRID(current_player->rid); @@ -205,8 +236,16 @@ namespace YimMenu::Submenus blipSpoofingGroup->AddItem(std::make_shared("spoofprimaryicon"_J, std::make_shared("primaryicon"_J, "Icon##primary"))); blipSpoofingGroup->AddItem(std::make_shared("spoofsecondaryicon"_J)); blipSpoofingGroup->AddItem(std::make_shared("spoofsecondaryicon"_J, std::make_shared("secondaryicon"_J, "Icon##secondary"))); + + auto discriminatorGroup = std::make_shared("", 1); + sessionSpoofingGroup->AddItem(std::make_shared("spoofdiscriminator"_J)); + discriminatorGroup->AddItem(std::make_shared("discriminator"_J)); + discriminatorGroup->AddItem(std::make_shared("copydiscriminator"_J, "Copy Current")); + sessionSpoofingGroup->AddItem(std::make_shared("spoofdiscriminator"_J, std::move(discriminatorGroup))); + spoofing->AddItem(nameChangerGroup); spoofing->AddItem(blipSpoofingGroup); + spoofing->AddItem(sessionSpoofingGroup); AddCategory(std::move(session)); AddCategory(std::move(spoofing)); AddCategory(std::move(database)); diff --git a/src/game/frontend/submenus/Players.cpp b/src/game/frontend/submenus/Players.cpp index e77ccca0..b541a0a6 100644 --- a/src/game/frontend/submenus/Players.cpp +++ b/src/game/frontend/submenus/Players.cpp @@ -2,8 +2,9 @@ #include "core/commands/BoolCommand.hpp" #include "core/commands/Commands.hpp" -#include "core/player_database/PlayerDatabase.hpp" +#include "core/frontend/widgets/imgui_colors.h" #include "game/backend/PlayerData.hpp" +#include "game/backend/PlayerDatabase.hpp" #include "game/backend/Players.hpp" #include "game/backend/Self.hpp" #include "game/commands/PlayerCommand.hpp" @@ -14,16 +15,17 @@ #include + // remove after testing #include "core/frontend/Notifications.hpp" #include "game/backend/FiberPool.hpp" #include "game/backend/ScriptMgr.hpp" #include "game/rdr/Entity.hpp" #include "game/rdr/Natives.hpp" +#include "game/rdr/Network.hpp" #include "game/rdr/Packet.hpp" #include "game/rdr/ScriptGlobal.hpp" #include "game/rdr/Scripts.hpp" -#include "util/VehicleSpawner.hpp" #include #include @@ -41,8 +43,32 @@ namespace YimMenu::Features namespace YimMenu::Submenus { - //bool popPlayerList = Features::_PopPlayerList.GetState(); - void drawPlayerList(bool external, float offset = 15.0f) + struct Tag + { + std::string Name; + ImVec4 Color; + }; + + static std::vector GetPlayerTags(YimMenu::Player player) + { + std::vector tags; + + if (player.IsHost()) + tags.push_back({"HOST", ImGui::Colors::DeepSkyBlue}); + + if (player.IsModder()) + tags.push_back({"MOD", ImGui::Colors::DeepPink}); + + if (player.GetPed() && player.GetPed().IsInvincible()) + tags.push_back({"GOD", ImGui::Colors::Crimson}); + + if (player.GetPed() && !player.GetPed().IsVisible()) + tags.push_back({"INVIS", ImGui::Colors::MediumPurple}); + + return tags; + } + + static void DrawPlayerList(bool external, float offset = 15.0f) { struct ComparePlayerNames { @@ -61,21 +87,40 @@ namespace YimMenu::Submenus { ImGui::SetNextWindowPos( ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowSize().x + offset, ImGui::GetWindowPos().y)); - ImGui::SetNextWindowSize(ImVec2(150, ImGui::GetWindowSize().y)); + ImGui::SetNextWindowSize(ImVec2(215, ImGui::GetWindowSize().y)); ImGui::Begin("Player List", nullptr, ImGuiWindowFlags_NoDecoration); ImGui::Checkbox("Spectate", &YimMenu::g_Spectating); for (auto& [id, player] : sortedPlayers) { std::string display_name = player.GetName(); - if (player.IsHost()) - { - display_name.append(" - Host"); - } if (ImGui::Selectable(display_name.c_str(), (YimMenu::Players::GetSelected() == player))) { YimMenu::Players::SetSelected(id); } + + if (player.IsModder() && ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + for (auto detection : player.GetData().m_Detections) + ImGui::BulletText("%s", g_PlayerDatabase->ConvertDetectionToDescription(detection).c_str()); + ImGui::EndTooltip(); + } + + auto tags = GetPlayerTags(player); + + auto old_item_spacing = ImGui::GetStyle().ItemSpacing.x; + + for (auto& tag : tags) + { + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, tag.Color); + ImGui::Text(("[" + tag.Name + "]").c_str()); + ImGui::PopStyleColor(); + ImGui::GetStyle().ItemSpacing.x = 1; + } + + ImGui::GetStyle().ItemSpacing.x = old_item_spacing; } ImGui::End(); } @@ -104,7 +149,7 @@ namespace YimMenu::Submenus auto playerOptionsGroup = std::make_shared("Info"); main->AddItem(std::make_shared([] { - drawPlayerList(true); + DrawPlayerList(true); })); playerOptionsGroup->AddItem(std::make_shared([] { @@ -113,6 +158,8 @@ namespace YimMenu::Submenus ImGui::Checkbox("Spectate", &YimMenu::g_Spectating); ImGui::Text(YimMenu::Players::GetSelected().GetName()); + ImGui::Text("Rank: %s", std::to_string(YimMenu::Players::GetSelected().GetRank())); + auto health = YimMenu::Players::GetSelected().GetPed().GetHealth(); auto maxHealth = YimMenu::Players::GetSelected().GetPed().GetMaxHealth(); std::string healthStr = std::format("HP: {}/{} ({:.2f}%)", health, maxHealth, (float)health / maxHealth * 100.0f); @@ -132,7 +179,7 @@ namespace YimMenu::Submenus ImGui::SetClipboardText(ridStr.c_str()); } - auto ip = YimMenu::Players::GetSelected().GetExternalIpAddress(); + auto ip = YimMenu::Players::GetSelected().GetExternalAddress(); ImGui::Text("IP Address:"); ImGui::SameLine(); auto ipStr = std::string(std::to_string(ip.m_field1)) @@ -162,6 +209,75 @@ namespace YimMenu::Submenus auto plyr = YimMenu::Players::GetSelected(); g_PlayerDatabase->AddPlayer(plyr.GetRID(), plyr.GetName()); } + + if (ImGui::Button("More Info")) + ImGui::OpenPopup("More Info"); + + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + if (ImGui::BeginPopupModal("More Info", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_Modal | ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("Language: %s", g_LanguageMap[YimMenu::Players::GetSelected().GetLanguage()].c_str()); + + auto honor = YimMenu::Players::GetSelected().GetHonor(); + std::string honorLevel; + + if (honor >= 0 && honor <= 7) + { + honorLevel = "Low"; + } + else if (honor > 7 && honor <= 10) + { + honorLevel = "Moderate"; + } + else if (honor > 10 && honor <= 15) + { + honorLevel = "High"; + } + else + { + honorLevel = "Invalid"; + } + + honorLevel += " (" + std::to_string(honor) + "/15)"; + ImGui::Text("Honor: %s", honorLevel.c_str()); + + ImGui::Text("District: %s", g_DistrictMap[YimMenu::Players::GetSelected().GetDistrict()].c_str()); + + ImGui::Text("Region: %s", g_RegionMap[YimMenu::Players::GetSelected().GetRegion()].c_str()); + + auto internalIp = YimMenu::Players::GetSelected().GetInternalAddress(); + ImGui::Text("Internal IP: %s", + std::format("{}.{}.{}.{}:{}", + static_cast(internalIp.m_field1), + static_cast(internalIp.m_field2), + static_cast(internalIp.m_field3), + static_cast(internalIp.m_field4), + YimMenu::Players::GetSelected().GetInternalPort()) + .c_str()); + + auto relayIp = YimMenu::Players::GetSelected().GetRelayAddress(); + ImGui::Text("Relay IP: %s", + std::format("{}.{}.{}.{}:{}", + static_cast(relayIp.m_field1), + static_cast(relayIp.m_field2), + static_cast(relayIp.m_field3), + static_cast(relayIp.m_field4), + YimMenu::Players::GetSelected().GetRelayPort()) + .c_str()); + + + ImGui::Text("Relay State: %u", YimMenu::Players::GetSelected().GetRelayState()); + + ImGui::Text("Average Latency: %.2f", YimMenu::Players::GetSelected().GetAverageLatency()); + ImGui::Text("Packet Loss: %.2f", YimMenu::Players::GetSelected().GetAveragePacketLoss()); + + ImGui::Spacing(); + + if (ImGui::Button("Close") || ((!ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered()) && ImGui::IsMouseClicked(ImGuiMouseButton_Left))) + ImGui::CloseCurrentPopup(); + + ImGui::EndPopup(); + } } else { @@ -175,6 +291,7 @@ namespace YimMenu::Submenus teleportGroup->AddItem(std::make_shared("tpintovehicle"_J)); teleportGroup->AddItem(std::make_shared("bring"_J)); teleportGroup->AddItem(std::make_shared("tpplayertowaypoint"_J)); + teleportGroup->AddItem(std::make_shared("tpplayertomadamnazar"_J)); teleportGroup->AddItem(std::make_shared("tpplayertojail"_J)); main->AddItem(playerOptionsGroup); @@ -186,7 +303,7 @@ namespace YimMenu::Submenus auto helpful = std::make_shared("Helpful"); helpful->AddItem(std::make_shared([] { - drawPlayerList(!Features::_PopPlayerList.GetState()); + DrawPlayerList(!Features::_PopPlayerList.GetState()); })); helpful->AddItem(std::make_shared([] { @@ -195,7 +312,7 @@ namespace YimMenu::Submenus FiberPool::Push([] { Vector3 coords = ENTITY::GET_ENTITY_COORDS(YimMenu::Players::GetSelected().GetPed().GetHandle(), true, true); float rot = ENTITY::GET_ENTITY_ROTATION(YimMenu::Players::GetSelected().GetPed().GetHandle(), 0).z; - SpawnVehicle("wagonarmoured01x", coords, rot); + Vehicle::Create("wagonarmoured01x"_J, coords, rot); Notifications::Show("Spawned Wagon", "Spawned Bounty Wagon for Player", NotificationType::Success); }); }; @@ -213,10 +330,9 @@ namespace YimMenu::Submenus float rot = (ENTITY::GET_ENTITY_ROTATION(ped, 0)).z; Vector3 pos = ENTITY::GET_ENTITY_COORDS(ped, true, true); - int handle = SpawnVehicle("huntercart01", + Vehicle::Create("huntercart01"_J, Vector3{pos.x + (dir.x * offset), pos.y + (dir.y * offset), pos.z}, ENTITY::GET_ENTITY_ROTATION(ped, 0).z); - PLAYER::_SET_PLAYER_HUNTING_WAGON(id, handle); Notifications::Show("Spawned Wagon", "Spawned Hunting Wagon for Player", NotificationType::Success); }); } @@ -229,7 +345,7 @@ namespace YimMenu::Submenus auto trolling = std::make_shared("Trolling"); trolling->AddItem(std::make_shared([] { - drawPlayerList(!Features::_PopPlayerList.GetState()); + DrawPlayerList(!Features::_PopPlayerList.GetState()); })); trolling->AddItem(std::make_shared("cageplayersmall"_J)); @@ -243,16 +359,17 @@ namespace YimMenu::Submenus auto toxic = std::make_shared("Toxic"); toxic->AddItem(std::make_shared([] { - drawPlayerList(true); + DrawPlayerList(true); })); - auto general = std::make_shared("General"); + auto general = std::make_shared("General"); general->AddItem(std::make_shared("kill"_J)); general->AddItem(std::make_shared("explode"_J)); general->AddItem(std::make_shared("lightning"_J)); general->AddItem(std::make_shared("defensive"_J)); general->AddItem(std::make_shared("offensive"_J)); - + general->AddItem(std::make_shared("remotebolas"_J)); + auto events = std::make_shared("Events"); events->AddItem(std::make_shared("maxhonor"_J)); events->AddItem(std::make_shared("minhonor"_J)); @@ -262,7 +379,7 @@ namespace YimMenu::Submenus events->AddItem(std::make_shared("sendticker"_J)); events->AddItem(std::make_shared("tickermessage"_J, "Message")); events->AddItem(std::make_shared("sendstablemountevent"_J)); - events->AddItem(std::make_shared("mountinstance"_J, "Instance")); + events->AddItem(std::make_shared("mountinstance"_J, "Instance")); events->AddItem(std::make_shared("stablemountevent"_J, "Event")); auto mount = std::make_shared("Mount"); @@ -279,7 +396,7 @@ namespace YimMenu::Submenus auto kick = std::make_shared("Kick"); kick->AddItem(std::make_shared([] { - drawPlayerList(true); + DrawPlayerList(true); })); kick->AddItem(std::make_shared("splitkick"_J)); diff --git a/src/game/frontend/submenus/Self.cpp b/src/game/frontend/submenus/Self.cpp index 1b538470..48affc14 100644 --- a/src/game/frontend/submenus/Self.cpp +++ b/src/game/frontend/submenus/Self.cpp @@ -124,10 +124,10 @@ namespace YimMenu::Submenus Self::Self() : Submenu::Submenu("Self") { - auto main = std::make_shared("Main"); - auto globalsGroup = std::make_shared("Globals"); - auto movementGroup = std::make_shared("Movement"); - auto toolsGroup = std::make_shared("Tools"); + auto main = std::make_shared("Main"); + auto globalsGroup = std::make_shared("Globals"); + auto movementGroup = std::make_shared("Movement"); + auto toolsGroup = std::make_shared("Tools"); globalsGroup->AddItem(std::make_shared("godmode"_J)); globalsGroup->AddItem(std::make_shared("neverwanted"_J)); @@ -151,8 +151,6 @@ namespace YimMenu::Submenus toolsGroup->AddItem(std::make_shared("npcignore"_J)); toolsGroup->AddItem(std::make_shared("eagleeye"_J)); - toolsGroup->AddItem(std::make_shared("spawnbountywagon"_J)); - toolsGroup->AddItem(std::make_shared("spawnhuntingwagon"_J)); toolsGroup->AddItem(std::make_shared("overridewhistle"_J)); toolsGroup->AddItem(std::make_shared("overridewhistle"_J, std::make_shared("whistlepitch"_J, "Pitch"))); @@ -162,13 +160,14 @@ namespace YimMenu::Submenus movementGroup->AddItem(std::make_shared("noclip"_J)); movementGroup->AddItem(std::make_shared("superjump"_J)); movementGroup->AddItem(std::make_shared("superrun"_J)); + movementGroup->AddItem(std::make_shared("freecam"_J)); main->AddItem(globalsGroup); main->AddItem(toolsGroup); main->AddItem(movementGroup); AddCategory(std::move(main)); - auto weapons = std::make_shared("Weapons"); + auto weapons = std::make_shared("Weapons"); auto weaponsGlobalsGroup = std::make_shared("Globals"); weaponsGlobalsGroup->AddItem(std::make_shared("infiniteammo"_J)); @@ -225,7 +224,5 @@ namespace YimMenu::Submenus })); AddCategory(std::move(animations)); - - } } diff --git a/src/game/frontend/submenus/Settings.cpp b/src/game/frontend/submenus/Settings.cpp index 02c471c8..7823ea34 100644 --- a/src/game/frontend/submenus/Settings.cpp +++ b/src/game/frontend/submenus/Settings.cpp @@ -4,6 +4,7 @@ #include "core/commands/HotkeySystem.hpp" #include "core/commands/LoopedCommand.hpp" #include "game/backend/Self.hpp" +#include "game/features/Features.hpp" #include "game/frontend/items/Items.hpp" namespace YimMenu::Submenus @@ -37,12 +38,31 @@ namespace YimMenu::Submenus auto hotkeys = std::make_shared("Hotkeys"); auto gui = std::make_shared("GUI"); auto protections = std::make_shared("Protection"); + auto esp = std::make_shared("ESP"); + auto context = std::make_shared("Context Menu"); + auto misc = std::make_shared("Misc"); + hotkeys->AddItem(std::make_shared(Hotkeys)); - gui->AddItem(std::make_shared("esp"_J)); - gui->AddItem(std::make_shared("ctxmenu"_J)); - gui->AddItem(std::make_shared("popplayerlist"_J)); + + esp->AddItem(std::make_shared("esp"_J)); + esp->AddItem(std::make_shared("esp"_J, std::make_shared("espname"_J, "Name"))); + esp->AddItem(std::make_shared("esp"_J, std::make_shared("espdistance"_J, "Distance"))); + esp->AddItem(std::make_shared("esp"_J, std::make_shared("espskeleton"_J, "Skeleton"))); + + context->AddItem(std::make_shared("ctxmenu"_J)); + context->AddItem(std::make_shared("ctxmenu"_J, std::make_shared("ctxmenuplayers"_J, "Players"))); + context->AddItem(std::make_shared("ctxmenu"_J, std::make_shared("ctxmenupeds"_J, "Peds"))); + context->AddItem(std::make_shared("ctxmenu"_J, std::make_shared("ctxmenuvehicles"_J, "Vehicles"))); + context->AddItem(std::make_shared("ctxmenu"_J, std::make_shared("ctxmenuobjects"_J, "Objects"))); + protections->AddItem(std::make_shared("detectspoofednames"_J)); protections->AddItem(std::make_shared("allowremotetp"_J)); + + misc->AddItem(std::make_shared("popplayerlist"_J)); + + gui->AddItem(esp); + gui->AddItem(context); + gui->AddItem(misc); AddCategory(std::move(hotkeys)); AddCategory(std::move(gui)); AddCategory(std::move(protections)); diff --git a/src/game/frontend/submenus/Teleport.cpp b/src/game/frontend/submenus/Teleport.cpp index ad20df7e..9ce41f41 100644 --- a/src/game/frontend/submenus/Teleport.cpp +++ b/src/game/frontend/submenus/Teleport.cpp @@ -2,7 +2,7 @@ #include "core/frontend/Notifications.hpp" #include "game/backend/FiberPool.hpp" -#include "game/bigfeatures/CustomTeleport.hpp" +#include "game/backend/SavedLocations.hpp" #include "game/backend/Self.hpp" #include "game/frontend/items/Items.hpp" #include "util/Math.hpp" @@ -11,27 +11,7 @@ namespace YimMenu::Submenus { - static Telelocation GetLocationPlayerIsClosestTo() - { - if (!Pointers.GetLocalPed) - return {}; - - float distance = 500; - Telelocation closestLocation{}; - - // saved_locations_filtered_list can be used to get a joint list of all categories when the filter is empty. - for (auto& loc : CustomTeleport::SavedLocationsFilteredList()) - { - float newDistance = Self::GetPed().GetPosition().GetDistance({loc.x, loc.y, loc.z}); - - if (newDistance < distance) - closestLocation = loc, distance = newDistance; - } - - return closestLocation; - } - - static float GetDistanceToTelelocation(Telelocation t) + static float GetDistanceFromLocation(const SavedLocation& t) { return rage::fvector3(t.x, t.y, t.z).GetDistance(Self::GetPed().GetPosition()); } @@ -39,30 +19,29 @@ namespace YimMenu::Submenus void RenderCustomTeleport() { ImGui::BeginGroup(); - static std::string NewLocationName{}; + static std::string newLocationName{}; static std::string category = "Default"; - static Telelocation deleteTelelocation; - static std::string filter{}; + static SavedLocation locationToDelete; - if (!std::string(deleteTelelocation.name).empty()) + if (!std::string(locationToDelete.name).empty()) ImGui::OpenPopup("##deletelocation"); if (ImGui::BeginPopupModal("##deletelocation", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { - ImGui::Text("Are you sure you want to delete %s?", deleteTelelocation.name); + ImGui::Text("Are you sure you want to delete %s?", locationToDelete.name); ImGui::Spacing(); if (ImGui::Button("Yes")) { - CustomTeleport::DeleteSavedLocation(category, deleteTelelocation.name); - deleteTelelocation.name = ""; + SavedLocations::DeleteSavedLocation(category, locationToDelete.name); + locationToDelete.name = ""; ImGui::CloseCurrentPopup(); } ImGui::SameLine(); if (ImGui::Button("No")) { - deleteTelelocation.name = ""; + locationToDelete.name = ""; ImGui::CloseCurrentPopup(); } @@ -72,23 +51,24 @@ namespace YimMenu::Submenus ImGui::PushItemWidth(300); InputTextWithHint("Category", "Category", &category).Draw(); - InputTextWithHint("Location name", "New location", &NewLocationName).Draw(); + ImGui::PushItemWidth(200); + InputTextWithHint("Location name", "New location", &newLocationName).Draw(); ImGui::PopItemWidth(); if (ImGui::Button("Save current location")) // Button widget still crashes { FiberPool::Push([=] { - if (NewLocationName.empty()) + if (newLocationName.empty()) { Notifications::Show("Custom Teleport", "Please enter a valid name.", NotificationType::Warning); } - else if (CustomTeleport::GetSavedLocationByName(NewLocationName)) + else if (SavedLocations::GetSavedLocationByName(newLocationName)) { - Notifications::Show("Custom Teleport", std::format("Location with the name {} already exists", NewLocationName)); + Notifications::Show("Custom Teleport", std::format("Location with the name {} already exists", newLocationName)); } else { - Telelocation teleportLocation; + SavedLocation teleportLocation; Entity teleportEntity = Self::GetPed(); if (auto vehicle = Self::GetVehicle()) teleportEntity = vehicle; @@ -96,14 +76,14 @@ namespace YimMenu::Submenus teleportEntity = mount; auto coords = teleportEntity.GetPosition(); - teleportLocation.name = NewLocationName; + teleportLocation.name = newLocationName; teleportLocation.x = coords.x; teleportLocation.y = coords.y; teleportLocation.z = coords.z; teleportLocation.yaw = ENTITY::GET_ENTITY_HEADING(teleportEntity.GetHandle()); teleportLocation.pitch = CAM::GET_GAMEPLAY_CAM_RELATIVE_PITCH(); teleportLocation.roll = CAM::GET_GAMEPLAY_CAM_RELATIVE_HEADING(); - CustomTeleport::SaveNewLocation(category, teleportLocation); + SavedLocations::SaveNewLocation(category, teleportLocation); } }); }; @@ -114,18 +94,25 @@ namespace YimMenu::Submenus ImGui::Text("Double click to teleport\nShift click to delete"); ImGui::Spacing(); + + static std::string filter{}; InputTextWithHint("##filter", "Search", &filter).Draw(); ImGui::BeginGroup(); ImGui::Text("Categories"); if (ImGui::BeginListBox("##categories", {200, -1})) { - for (auto& l : CustomTeleport::GetAllSavedLocations() | std::ranges::views::keys) + for (auto& l : SavedLocations::GetAllSavedLocations() | std::ranges::views::keys) { if (ImGui::Selectable(l.data(), l == category)) { category = l; } + + if (category.empty()) + { + category = l; + } } ImGui::EndListBox(); } @@ -133,24 +120,24 @@ namespace YimMenu::Submenus ImGui::SameLine(); ImGui::BeginGroup(); ImGui::Text("Locations"); - if (ImGui::BeginListBox("##telelocations", {200, -1})) // Need automatic dimensions instead of hard coded + if (ImGui::BeginListBox("##saved_locs", {200, -1})) // Need automatic dimensions instead of hard coded { - if (CustomTeleport::GetAllSavedLocations().find(category) != CustomTeleport::GetAllSavedLocations().end()) + if (SavedLocations::GetAllSavedLocations().find(category) != SavedLocations::GetAllSavedLocations().end()) { - std::vector current_list{}; + std::vector current_list{}; if (!filter.empty()) - current_list = CustomTeleport::SavedLocationsFilteredList(filter); + current_list = SavedLocations::SavedLocationsFilteredList(filter); else - current_list = CustomTeleport::GetAllSavedLocations().at(category); + current_list = SavedLocations::GetAllSavedLocations().at(category); for (const auto& l : current_list) { - if (ImGui::Selectable(l.name.data(), l.name == GetLocationPlayerIsClosestTo().name, ImGuiSelectableFlags_AllowDoubleClick)) + if (ImGui::Selectable(l.name.data(), false, ImGuiSelectableFlags_AllowDoubleClick)) { if (GetAsyncKeyState(VK_SHIFT) & 0x8000) { - deleteTelelocation = l; + locationToDelete = l; } else { @@ -163,12 +150,13 @@ namespace YimMenu::Submenus } } } + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); if (l.name.length() > 27) ImGui::Text(l.name.data()); - ImGui::Text("Distance: %f", GetDistanceToTelelocation(l)); + ImGui::Text("Distance: %f", GetDistanceFromLocation(l)); ImGui::EndTooltip(); } } @@ -206,4 +194,4 @@ namespace YimMenu::Submenus AddCategory(std::move(main)); AddCategory(std::move(customteleport)); } -} \ No newline at end of file +} diff --git a/src/game/frontend/submenus/World.cpp b/src/game/frontend/submenus/World.cpp index 18f86d6e..74817471 100644 --- a/src/game/frontend/submenus/World.cpp +++ b/src/game/frontend/submenus/World.cpp @@ -2,6 +2,7 @@ #include "World/PedSpawner.hpp" #include "World/Shows.hpp" +#include "World/Train.hpp" #include "World/VehicleSpawner.hpp" #include "World/Weather.hpp" #include "core/commands/Commands.hpp" @@ -11,8 +12,6 @@ #include "game/backend/ScriptMgr.hpp" #include "game/backend/Self.hpp" #include "game/frontend/items/Items.hpp" -#include "util/VehicleSpawner.hpp" - #include @@ -80,6 +79,7 @@ namespace YimMenu::Submenus auto spawners = std::make_shared("Spawners"); auto pedSpawnerGroup = std::make_shared("Ped Spawner"); auto vehicleSpawnerGroup = std::make_shared("Vehicle Spawner"); + auto trainSpawnerGroup = std::make_shared("Train Spawner"); pedSpawnerGroup->AddItem(std::make_shared([] { RenderPedSpawnerMenu(); @@ -89,14 +89,29 @@ namespace YimMenu::Submenus RenderVehicleSpawnerMenu(); })); + trainSpawnerGroup->AddItem(std::make_shared([] { + RenderTrainsMenu(); + })); + spawners->AddItem(pedSpawnerGroup); spawners->AddItem(vehicleSpawnerGroup); + spawners->AddItem(trainSpawnerGroup); - auto killPeds = std::make_shared("", 1); + auto killPeds = std::make_shared("Kill", 1); killPeds->AddItem(std::make_shared("killallpeds"_J)); killPeds->AddItem(std::make_shared("killallenemies"_J)); + auto deleteOpts = std::make_shared("Delete", 1); + deleteOpts->AddItem(std::make_shared("delpeds"_J)); + deleteOpts->AddItem(std::make_shared("delvehs"_J)); + deleteOpts->AddItem(std::make_shared("delobjs"_J)); + auto bringOpts = std::make_shared("Bring", 1); + bringOpts->AddItem(std::make_shared("bringpeds"_J)); + bringOpts->AddItem(std::make_shared("bringvehs"_J)); + bringOpts->AddItem(std::make_shared("bringobjs"_J)); main->AddItem(std::move(killPeds)); + main->AddItem(std::move(deleteOpts)); + main->AddItem(std::move(bringOpts)); main->AddItem(std::make_shared("disableguardzones"_J)); main->AddItem(std::make_shared("forcelighting"_J)); diff --git a/src/game/frontend/submenus/World/PedSpawner.cpp b/src/game/frontend/submenus/World/PedSpawner.cpp index 67d04f5e..a1f2b6be 100644 --- a/src/game/frontend/submenus/World/PedSpawner.cpp +++ b/src/game/frontend/submenus/World/PedSpawner.cpp @@ -7,6 +7,7 @@ #include "game/backend/ScriptMgr.hpp" #include "game/backend/Self.hpp" #include "game/frontend/items/Items.hpp" +#include "game/rdr/Enums.hpp" #include "game/rdr/Natives.hpp" #include "game/rdr/data/PedModels.hpp" @@ -81,7 +82,8 @@ namespace YimMenu::Submenus static std::string pedModelBuffer; static float scale = 1; - static bool dead, invis, godmode, freeze; + static bool dead, invis, godmode, freeze, companion; + static std::vector spawnedPeds; InputTextWithHint("##pedmodel", "Ped Model", &pedModelBuffer, ImGuiInputTextFlags_CallbackCompletion, nullptr, PedSpawnerInputCallback) .Draw(); if (ImGui::IsItemHovered()) @@ -109,11 +111,70 @@ namespace YimMenu::Submenus ImGui::Checkbox("Invisible", &invis); ImGui::Checkbox("GodMode", &godmode); ImGui::Checkbox("Frozen", &freeze); + ImGui::Checkbox("Companion", &companion); ImGui::SliderFloat("Scale", &scale, 0.1, 10); if (ImGui::Button("Spawn")) { FiberPool::Push([] { - Ped::Create(Joaat(pedModelBuffer), Self::GetPed().GetPosition(), 0, freeze, dead, godmode, invis, scale); + auto ped = Ped::Create(Joaat(pedModelBuffer), Self::GetPed().GetPosition()); + + if (!ped) + return; + + if (freeze) + ped.SetFrozen(true); + + if (dead) + ped.Kill(); + + if (godmode) + ped.SetInvincible(true); + + if (invis) + ped.SetVisible(false); + + if (scale != 1.0f) + ped.SetScale(scale); + + spawnedPeds.push_back(ped); + + if (companion) + { + int group = PED::GET_PED_GROUP_INDEX(YimMenu::Self::GetPed().GetHandle()); + if (!PED::DOES_GROUP_EXIST(group)) + { + group = PED::CREATE_GROUP(0); + PED::SET_PED_AS_GROUP_LEADER(YimMenu::Self::GetPed().GetHandle(), group, true); + } + + ENTITY::SET_ENTITY_AS_MISSION_ENTITY(ped.GetHandle(), true, false); + PED::SET_PED_AS_GROUP_MEMBER(ped.GetHandle(), group); + PED::SET_PED_CAN_BE_TARGETTED_BY_PLAYER(ped.GetHandle(), YimMenu::Self::GetPlayer().GetId(), false); + PED::SET_PED_RELATIONSHIP_GROUP_HASH(ped.GetHandle(), + PED::GET_PED_RELATIONSHIP_GROUP_HASH(YimMenu::Self::GetPed().GetHandle())); + DECORATOR::DECOR_SET_INT(ped.GetHandle(), "SH_CMP_companion", 1); + ped.SetConfigFlag(PedConfigFlag::UseFollowLeaderThreatResponse, true); + ped.SetMotivation(MotivationState::BRAVE_STATE, 100.f); + PED::SET_PED_COMBAT_ATTRIBUTES(ped.GetHandle(), 58, false); + PED::SET_PED_COMBAT_ATTRIBUTES(ped.GetHandle(), 38, false); + PED::SET_PED_OWNS_ANIMAL(Self::GetPed().GetHandle(), ped.GetHandle(), true); + + auto blip = MAP::BLIP_ADD_FOR_ENTITY("BLIP_STYLE_COMPANION"_J, ped.GetHandle()); + MAP::BLIP_ADD_MODIFIER(blip, "BLIP_MODIFIER_COMPANION_DOG"_J); + + if (ped.IsAnimal()) + { + FLOCK::SET_ANIMAL_TUNING_BOOL_PARAM(ped.GetHandle(), 44, 0); + FLOCK::SET_ANIMAL_TUNING_BOOL_PARAM(ped.GetHandle(), 32, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 74, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 80, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 115, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 117, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 119, 1); + FLOCK::SET_ANIMAL_TUNING_FLOAT_PARAM(ped.GetHandle(), 165, 5); + FLOCK::_SET_ANIMAL_IS_WILD(ped.GetHandle(), false); + } + } }); } ImGui::SameLine(); @@ -134,6 +195,27 @@ namespace YimMenu::Submenus STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(model); }); } + ImGui::SameLine(); + if (ImGui::Button("Cleanup Peds")) + { + FiberPool::Push([] { + for (auto it = spawnedPeds.begin(); it != spawnedPeds.end();) + { + if (it->IsValid()) + { + if (it->GetMount()) + { + it->GetMount().ForceControl(); + it->GetMount().Delete(); + } + + it->ForceControl(); + it->Delete(); + } + it = spawnedPeds.erase(it); + } + }); + } ImGui::PopID(); } diff --git a/src/game/frontend/submenus/World/Shows.cpp b/src/game/frontend/submenus/World/Shows.cpp index 9a6b1a23..15448eb4 100644 --- a/src/game/frontend/submenus/World/Shows.cpp +++ b/src/game/frontend/submenus/World/Shows.cpp @@ -1,15 +1,17 @@ #include "Shows.hpp" + +#include "game/backend/FiberPool.hpp" #include "game/backend/NativeHooks.hpp" -#include "game/rdr/Natives.hpp" -#include "game/rdr/Scripts.hpp" +#include "game/backend/Players.hpp" +#include "game/backend/ScriptMgr.hpp" #include "game/backend/Self.hpp" +#include "game/rdr/Natives.hpp" #include "game/rdr/Player.hpp" -#include "game/backend/FiberPool.hpp" -#include "game/backend/ScriptMgr.hpp" -#include "game/backend/Players.hpp" +#include "game/rdr/Scripts.hpp" #include + namespace YimMenu::Submenus { enum class ActorOverrideType @@ -42,7 +44,7 @@ namespace YimMenu::Submenus BAND_02, }; - constexpr auto g_SceneTypeScripts = std::to_array({ + constexpr auto g_SceneTypeScriptsMP = std::to_array({ "show_mp_nbx_cancan_01"_J, "show_mp_nbx_cancan_02"_J, "show_mp_nbx_firebreath"_J, @@ -58,6 +60,22 @@ namespace YimMenu::Submenus "show_mp_nbx_bigband_02"_J, }); + constexpr auto g_SceneTypeScriptsSP = std::to_array({ + "show_nbx_cancan"_J, + "show_nbx_cancan_02"_J, + "show_nbx_firebreath"_J, + "show_nbx_firedance_01"_J, + "show_nbx_firedance_02"_J, + "show_nbx_snakedance_01"_J, + "show_nbx_snakedance_02"_J, + "show_nbx_sworddancer"_J, + "show_nbx_oddfellows"_J, + "show_nbx_escapeartist"_J, + "show_nbx_flexfight"_J, + "show_nbx_bigband"_J, + "show_nbx_bigband_02"_J, + }); + constexpr auto g_SceneTypeStrs = std::to_array({ "Cancan Dance (1)", "Cancan Dance (2)", @@ -98,14 +116,194 @@ namespace YimMenu::Submenus // data static SceneType g_SelectedSceneType = SceneType::CAN_CAN_01; - static int g_RunningSceneScriptID = -1; - static std::vector<::Entity> g_ShowEntities; + static int g_RunningSceneScriptID = -1; + static int g_RunningSceneAnimscene = -1; + static bool g_AutoCleanup = true; + static bool g_SpawnAudience = true; + static std::vector g_ShowEntities; + static std::vector g_AudienceMembers; + constexpr int NUM_AUDIENCE_MEMBERS = 56; + + + // audience creation code from SP + + static rage::fvector3 GetAudienceMemberPos(int idx) + { + switch (idx) + { + case 0: return {2541.9539f, -1303.6516f, 47.51162f}; + case 1: return {2542.6248f, -1303.6276f, 47.50835f}; + case 2: return {2543.2527f, -1303.5038f, 47.51194f}; + case 3: return {2543.9138f, -1303.4467f, 47.50978f}; + case 4: return {2544.5544f, -1303.3499f, 47.51124f}; + case 5: return {2545.2117f, -1303.2858f, 47.48675f}; + case 6: return {2540.8508f, -1302.3906f, 47.83032f}; + case 7: return {2541.4048f, -1302.1624f, 47.83151f}; + case 8: return {2542.039f, -1301.9946f, 47.83165f}; + case 9: return {2542.659f, -1301.8953f, 47.83114f}; + case 10: return {2543.2808f, -1301.7847f, 47.83141f}; + case 11: return {2543.8872f, -1301.7189f, 47.8308f}; + case 12: return {2544.5361f, -1301.6354f, 47.831f}; + case 13: return {2545.165f, -1301.5907f, 47.81311f}; + case 14: return {2540.8162f, -1300.6383f, 48.12306f}; + case 15: return {2541.43f, -1300.4728f, 48.12244f}; + case 16: return {2542.0337f, -1300.3115f, 48.12096f}; + case 17: return {2542.644f, -1300.1532f, 48.12228f}; + case 18: return {2543.269f, -1300.0386f, 48.12248f}; + case 19: return {2543.8955f, -1299.9259f, 48.12423f}; + case 20: return {2545.1692f, -1299.8176f, 48.10023f}; + case 21: return {2540.8438f, -1298.8798f, 48.39516f}; + case 22: return {2541.4421f, -1298.742f, 48.39409f}; + case 23: return {2542.0696f, -1298.5867f, 48.39284f}; + case 24: return {2543.3018f, -1298.2754f, 48.39411f}; + case 25: return {2543.8982f, -1298.1788f, 48.39465f}; + case 26: return {2544.5361f, -1298.0916f, 48.39633f}; + case 27: return {2550.9575f, -1303.6145f, 47.48922f}; + case 28: return {2550.3018f, -1303.5435f, 47.48922f}; + case 29: return {2549.651f, -1303.4829f, 47.48394f}; + case 30: return {2549.0054f, -1303.4297f, 47.48394f}; + case 31: return {2548.3562f, -1303.3667f, 47.48394f}; + case 32: return {2547.7126f, -1303.341f, 47.48394f}; + case 33: return {2552.0967f, -1302.3553f, 47.80622f}; + case 34: return {2551.5093f, -1302.1925f, 47.80622f}; + case 35: return {2550.8994f, -1302.0336f, 47.80622f}; + case 36: return {2550.2979f, -1301.8839f, 47.80622f}; + case 37: return {2549.6611f, -1301.7599f, 47.80622f}; + case 38: return {2549.0374f, -1301.6827f, 47.80622f}; + case 39: return {2548.4128f, -1301.6241f, 47.80622f}; + case 40: return {2552.1223f, -1300.5559f, 48.09521f}; + case 41: return {2551.4993f, -1300.4144f, 48.09521f}; + case 42: return {2550.8713f, -1300.2426f, 48.09521f}; + case 43: return {2550.2546f, -1300.1294f, 48.09521f}; + case 44: return {2549.6353f, -1300.0294f, 48.09521f}; + case 45: return {2549.016f, -1299.9486f, 48.09521f}; + case 46: return {2552.1152f, -1298.8127f, 48.36841f}; + case 47: return {2551.4988f, -1298.6577f, 48.36841f}; + case 48: return {2550.2537f, -1298.388f, 48.36841f}; + case 49: return {2549.629f, -1298.3119f, 48.36841f}; + case 50: return {2549.001f, -1298.207f, 48.36841f}; + case 51: return {2548.3677f, -1298.1227f, 48.36841f}; + case 52: return {2547.7332f, -1298.0409f, 48.36841f}; + case 53: return {2553.102f, -1299.6674f, 49.214f}; + case 54: return {2553.1287f, -1302.3986f, 49.214f}; + case 55: return {2539.7886f, -1302.3699f, 49.214f}; + default: return {}; + } + } + + static float GetAudienceMemberHeading(int idx) + { + switch (idx) + { + case 0: return 189.76f; + case 1: return 194.54f; + case 2: return 185.02f; + case 3: return 185.67f; + case 4: return 186.48f; + case 5: return 189.64f; + case 6: return 194.87f; + case 7: return 197.45f; + case 8: return 192.94f; + case 9: return 190.4f; + case 10: return 187.74f; + case 11: return 188.21f; + case 12: return 191.46f; + case 13: return 187.8f; + case 14: return 197.77f; + case 15: return 197.28f; + case 16: return 195.7f; + case 17: return 194.38f; + case 18: return 189.91f; + case 19: return 187.19f; + case 20: return 183.35f; + case 21: return 195.68f; + case 22: return 195.08f; + case 23: return 197.6f; + case 24: return 192.22f; + case 25: return 187.31f; + case 26: return 186.63f; + case 27: return 174.21f; + case 28: return 175.4f; + case 29: return 177.33f; + case 30: return 177.62f; + case 31: return 175.4f; + case 32: return 176.59f; + case 33: return 165.32f; + case 34: return 170.16f; + case 35: return 170.37f; + case 36: return 174.13f; + case 37: return 175.59f; + case 38: return 173.64f; + case 39: return 178.62f; + case 40: return 169.96f; + case 41: return 171.41f; + case 42: return 170.19f; + case 43: return 171.15f; + case 44: return 174.93f; + case 45: return 177.61f; + case 46: return 169.6f; + case 47: return 171.53f; + case 48: return 172.77f; + case 49: return 174.2f; + case 50: return 175.33f; + case 51: return 175.1f; + case 52: return 176.09f; + case 53: return 152.8307f; + case 54: return 152.8307f; + case 55: return 190.6648f; + default: return 0.0f; + } + } + + static Ped CreateAudienceMemberForSlot(int idx) + { + auto position = GetAudienceMemberPos(idx); + auto heading = GetAudienceMemberHeading(idx); + auto model = POPULATION::GET_RANDOM_MODEL_FROM_POPULATION_SET("nbx_civilians"_J, idx < 12 ? 2 : 0, -156825994, false, true, position.x, position.y, position.z); // the model is already loaded in memory + + if (model == 0) + return nullptr; + + auto ped = Ped::Create(model, position, heading); + ped.SetInvincible(true); + PED::SET_PED_KEEP_TASK(ped.GetHandle(), true); + + return ped; + } + + static void StartAudienceMemberTask(Ped ped, int idx) + { + auto position = GetAudienceMemberPos(idx); + auto heading = GetAudienceMemberHeading(idx); + + TASK::TASK_START_SCENARIO_AT_POSITION(ped.GetHandle(), "PROP_HUMAN_SEAT_CHAIR"_J, position.x, position.y, position.z, heading, -1, false, true, nullptr, 0.25f, false); + } + + static void CreateAudienceMembers() + { + g_AudienceMembers.resize(NUM_AUDIENCE_MEMBERS, nullptr); + for (int i = 0; i < NUM_AUDIENCE_MEMBERS; i++) + { + auto ped = CreateAudienceMemberForSlot(i); + StartAudienceMemberTask(ped, i); + g_AudienceMembers[i] = ped; + } + } static SceneType SceneTypeFromScript(joaat_t script) { - for (auto i = 0; i < g_SceneTypeScripts.size(); i++) - if (g_SceneTypeScripts[i] == script) - return SceneType(i); + if (*Pointers.IsSessionStarted) + { + for (auto i = 0; i < g_SceneTypeScriptsMP.size(); i++) + if (g_SceneTypeScriptsMP[i] == script) + return SceneType(i); + } + else + { + for (auto i = 0; i < g_SceneTypeScriptsSP.size(); i++) + if (g_SceneTypeScriptsSP[i] == script) + return SceneType(i); + } return SceneType(0); // should not reach here } @@ -115,7 +313,9 @@ namespace YimMenu::Submenus if (def.Type == ActorOverrideType::DEFAULT) return nullptr; else if (def.Type == ActorOverrideType::SELF) + { return Self::GetPed(); + } else { if (!def.OverridePlayer.IsValid()) @@ -169,7 +369,8 @@ namespace YimMenu::Submenus switch (hash) { case "CS_ESCAPEARTIST"_J: return ProcessActorDef(g_EscapeArtistOverride); - case "CS_ESCAPEARTISTASSISTANT"_J: return ProcessActorDef(g_EscapeArtistAssistantOverride); + case "CS_ESCAPEARTISTASSISTANT"_J: + return ProcessActorDef(g_EscapeArtistAssistantOverride); // note that the band member isn't actually used in the scene, so we aren't adding an override for that }; } @@ -206,6 +407,7 @@ namespace YimMenu::Submenus auto ped = PED::CREATE_PED(ctx->GetArg(0), ctx->GetArg(1), ctx->GetArg(2), ctx->GetArg(3), ctx->GetArg(4), ctx->GetArg(5), ctx->GetArg(6), ctx->GetArg(7), ctx->GetArg(8)); g_ShowEntities.push_back(ped); + Ped(ped).SetInvincible(true); ctx->SetReturnValue(std::move(ped)); } @@ -219,6 +421,7 @@ namespace YimMenu::Submenus ENTITY::SET_ENTITY_COLLISION(obj, false, false); } g_ShowEntities.push_back(obj); + Entity(obj).SetInvincible(true); ctx->SetReturnValue(std::move(obj)); } @@ -247,13 +450,17 @@ namespace YimMenu::Submenus } } }); + g_RunningSceneAnimscene = handle; ctx->SetReturnValue(std::move(handle)); } inline void RenderActorDef(ActorDefinition& def, const std::string& name) { ImGui::SetNextItemWidth(100); - ImGui::Combo(name.c_str(), (int*)&def.Type, "Default\0Yourself\0Player\0"); + if (*Pointers.IsSessionStarted) + ImGui::Combo(name.c_str(), (int*)&def.Type, "Default\0Yourself\0Player\0"); + else + ImGui::Combo(name.c_str(), (int*)&def.Type, "Default\0Yourself\0"); if (def.Type == ActorOverrideType::PLAYER) { ImGui::SameLine(); @@ -279,20 +486,66 @@ namespace YimMenu::Submenus } } + static void ShutdownShow() + { + SCRIPTS::TERMINATE_THREAD(g_RunningSceneScriptID); + MISC::CLEAR_AREA(2546.5646f, -1301.4119f, 48.3564f, 500.0f, -1); // clear stage area + for (auto& entity : g_ShowEntities) + { + entity.Delete(); + } + for (auto& entity : g_AudienceMembers) + { + if (entity) + { + entity.Delete(); + } + } + g_ShowEntities.clear(); + g_AudienceMembers.clear(); + g_RunningSceneScriptID = -1; + g_RunningSceneAnimscene = -1; + } + + static void ShowsTick() + { + while (g_Running) + { + if (g_RunningSceneScriptID != -1 && g_RunningSceneAnimscene != -1) + { + if (ANIMSCENE::_IS_ANIM_SCENE_PAUSED(g_RunningSceneAnimscene) || ANIMSCENE::IS_ANIM_SCENE_FINISHED(g_RunningSceneAnimscene, false)) + { + ShutdownShow(); + return; + } + } + ScriptMgr::Yield(); + } + } + void RenderShowsMenu() { static bool _run_once = ([] { - for (auto& script : g_SceneTypeScripts) - { + static auto hook_natives = [](auto& script) { NativeHooks::AddHook(script, NativeIndex::CREATE_PED, CREATE_PED); NativeHooks::AddHook(script, NativeIndex::NETWORK_HAS_CONTROL_OF_ENTITY, NETWORK_HAS_CONTROL_OF_ENTITY); NativeHooks::AddHook(script, NativeIndex::CREATE_OBJECT, CREATE_OBJECT); NativeHooks::AddHook(script, NativeIndex::_CREATE_ANIM_SCENE, CREATE_ANIM_SCENE); - } + }; + + for (auto& script : g_SceneTypeScriptsMP) + hook_natives(script); + + for (auto& script : g_SceneTypeScriptsSP) + hook_natives(script); + + ScriptMgr::AddScript(std::make_unique