diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a2d1ce3..515042e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,4 +54,4 @@ add_compile_definitions(YimMenu "_CRT_SECURE_NO_WARNINGS" "NOMINMAX" "WIN32_LEAN_AND_MEAN" -) +) \ No newline at end of file diff --git a/src/backend/backend.cpp b/src/backend/backend.cpp index bf4edb84..4bb3c5fe 100644 --- a/src/backend/backend.cpp +++ b/src/backend/backend.cpp @@ -4,11 +4,15 @@ #include "looped/looped.hpp" #include "services/context_menu/context_menu_service.hpp" #include "script_patches.hpp" +#include "looped_command.hpp" namespace big { void backend::loop() { + for (auto& command : g_looped_commands) + command->refresh(); + register_script_patches(); while (g_running) @@ -20,6 +24,10 @@ namespace big looped::system_mission_creator(); looped::system_auto_tp(); + for (auto command : g_looped_commands) + if (command->is_enabled()) + command->on_tick(); + script::get_current()->yield(); } } @@ -30,20 +38,9 @@ namespace big while (g_running) { - looped::self_clean_player(); - looped::self_free_cam(); looped::self_godmode(); - looped::self_invisibility(); - looped::self_no_ragdoll(); - looped::self_off_radar(); looped::self_police(); - looped::self_super_run(); - looped::self_no_collision(); looped::self_hud(); - looped::self_unlimited_oxygen(); - looped::self_no_water_collision(); - looped::self_mobile_radio(); - looped::self_fast_respawn(); looped::self_dance_mode(); script::get_current()->yield(); @@ -59,17 +56,11 @@ namespace big looped::weapons_ammo_special_type(); looped::weapons_cage_gun(); looped::weapons_delete_gun(); - looped::weapons_force_crosshairs(); looped::weapons_gravity_gun(); looped::weapons_increased_damage(); - looped::weapons_infinite_ammo(); - looped::weapons_infinite_mag(); - looped::weapons_no_recoil(); - looped::weapons_no_spread(); looped::weapons_repair_gun(); looped::weapons_steal_vehicle_gun(); looped::weapons_vehicle_gun(); - looped::weapons_rapid_fire(); script::get_current()->yield(); } @@ -83,16 +74,8 @@ namespace big { looped::vehicle_auto_drive(); looped::vehicle_boost_behavior(); - looped::vehicle_drive_on_water(); looped::vehicle_god_mode(); - looped::vehicle_horn_boost(); - looped::vehicle_jump(); - looped::vehicle_instant_brake(); - looped::vehicle_is_targetable(); - looped::vehicle_seatbelt(); looped::vehicle_speedo_meter(); - looped::vehicle_keep_vehicle_repaired(); - looped::vehicle_no_water_collision(); script::get_current()->yield(); } @@ -117,7 +100,6 @@ namespace big while (g_running) { looped::hud_transition_state(); - looped::tunables_disable_phone(); looped::session_local_time(); looped::session_pop_multiplier_areas(); looped::session_force_thunder(); @@ -142,18 +124,6 @@ namespace big } } - void backend::noclip_loop() - { - LOG(INFO) << "Starting script: No clip"; - - while (g_running) - { - looped::self_noclip(); - - script::get_current()->yield(); - } - } - void backend::lscustoms_loop() { LOG(INFO) << "Starting script: Ls customs"; @@ -196,11 +166,8 @@ namespace big while (g_running) { - looped::self_free_cam_disable_control_action(); - looped::self_noclip_disable_control_action(); looped::custom_gun_disable_control_action(); - context_menu_service::disable_control_action_loop(); script::get_current()->yield(); diff --git a/src/backend/backend.hpp b/src/backend/backend.hpp index cf3233e0..b6793ec9 100644 --- a/src/backend/backend.hpp +++ b/src/backend/backend.hpp @@ -13,7 +13,6 @@ namespace big static void turnsignal_loop(); static void misc_loop(); static void remote_loop(); - static void noclip_loop(); static void lscustoms_loop(); static void rainbowpaint_loop(); static void vehiclefly_loop(); diff --git a/src/backend/bool_command.cpp b/src/backend/bool_command.cpp new file mode 100644 index 00000000..1ff5ca88 --- /dev/null +++ b/src/backend/bool_command.cpp @@ -0,0 +1,62 @@ +#include "bool_command.hpp" + +namespace big +{ + bool_command::bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle) : + command(name, label, description, std::nullopt), + m_toggle(toggle) + { + } + + void bool_command::execute(const std::vector& args, const std::shared_ptr ctx) + { + if (args.size() == 0) + { + if (is_enabled()) + { + m_toggle = false; + ctx->report_output(std::format("{} has been disabled", m_label)); + } + else + { + m_toggle = true; + ctx->report_output(std::format("{} has been enabled", m_label)); + } + } + else + { + m_toggle = args[0]; + } + + this->refresh(); + } + + std::optional> bool_command::parse_args(const std::vector& args, const std::shared_ptr ctx) + { + std::vector result; + + if (args.size() == 0) + return result; + + if (args.size() > 1) + { + ctx->report_error(std::format("Too many arguments passed to command {}, Expected 1 or less, got {}", m_name, args.size())); + return std::nullopt; + } + + if (args[0] == "yes" || args[0] == "on" || args[0] == "enable" || args[0] == "true") + { + result.push_back(1); + return result; + } + + if (args[0] == "no" || args[0] == "off" || args[0] == "disable" || args[0] == "false") + { + result.push_back(0); + return result; + } + + ctx->report_error(std::format("Cannot convert\"{}\" into a boolean in command {}", args[0], m_name)); + return std::nullopt; + } +} \ No newline at end of file diff --git a/src/backend/bool_command.hpp b/src/backend/bool_command.hpp new file mode 100644 index 00000000..7bd08f49 --- /dev/null +++ b/src/backend/bool_command.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "command.hpp" + +namespace big +{ + class bool_command : public command + { + protected: + bool& m_toggle; + virtual void execute(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + public: + bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle); + inline bool& is_enabled() { return m_toggle; } + + virtual void refresh() {}; + virtual void enable() { m_toggle = true; }; + virtual void disable() { m_toggle = false; }; + }; +} \ No newline at end of file diff --git a/src/backend/command.cpp b/src/backend/command.cpp new file mode 100644 index 00000000..f4a022e5 --- /dev/null +++ b/src/backend/command.cpp @@ -0,0 +1,112 @@ +#include "command.hpp" +#include "fiber_pool.hpp" + +namespace +{ + // https://stackoverflow.com/a/7408245 + static std::vector split(const std::string& text, char sep) + { + std::vector tokens; + std::size_t start = 0, end = 0; + while ((end = text.find(sep, start)) != std::string::npos) + { + if (end != start) + { + tokens.push_back(text.substr(start, end - start)); + } + start = end + 1; + } + if (end != start) + { + tokens.push_back(text.substr(start)); + } + return tokens; + } +} + +namespace big +{ + command::command(const std::string& name, const std::string& label, const std::string& description, std::optional num_args, bool fiber_pool) : + m_name(name), + m_label(label), + m_description(description), + m_num_args(num_args), + m_fiber_pool(fiber_pool) + { + g_commands[rage::joaat(name)] = this; + } + + void command::call(const std::vector& args, const std::shared_ptr ctx) + { + if (m_num_args.has_value() && args.size() != m_num_args.value()) + { + ctx->report_error(std::format("Command {} called with the wrong number of arguments. Expected {}, got {}", m_name, m_num_args.value(), args.size())); + return; + } + + if (ctx->get_access_level() < get_access_level()) + { + ctx->report_error(std::format("You do not have sufficient permissions to call command {}", m_name)); + return; + } + + if (m_fiber_pool) + g_fiber_pool->queue_job([this, args, ctx] { execute(args, ctx); }); + else + execute(args, ctx); + } + + void command::call(const std::vector& args, const std::shared_ptr ctx) + { + if (m_num_args.has_value() && args.size() != m_num_args.value()) + { + ctx->report_error(std::format("Command {} called with the wrong number of arguments. Expected {}, got {}", m_name, m_num_args.value(), args.size())); + return; + } + + if (ctx->get_access_level() < get_access_level()) + { + ctx->report_error(std::format("You do not have sufficient permissions to call command {}", m_name)); + return; + } + + auto parsed = parse_args(args, ctx); + if (parsed.has_value()) + call(parsed.value(), ctx); + } + + command* command::get(rage::joaat_t command) + { + return g_commands[command]; + } + + void command::call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx) + { + g_commands[command]->call(args, ctx); + } + + void command::call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx) + { + g_commands[command]->call(args, ctx); + } + + void command::process(const std::string& text, const std::shared_ptr ctx) + { + auto args = split(text, ' '); + if (args.size() == 0 || args[0].empty()) + { + ctx->report_error("No command to call"); + return; + } + + std::uint32_t hash = rage::joaat(args[0]); + if (!g_commands.contains(hash)) + { + ctx->report_error(std::format("Command {} does not exist", args[0])); + return; + } + + args.erase(args.begin()); + call(hash, args, ctx); + } +} \ No newline at end of file diff --git a/src/backend/command.hpp b/src/backend/command.hpp new file mode 100644 index 00000000..2277cb01 --- /dev/null +++ b/src/backend/command.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "gta/joaat.hpp" +#include "core/enums.hpp" +#include "context/command_context.hpp" +#include "context/default_command_context.hpp" + +namespace big +{ + class command + { + protected: + std::string m_name; + std::string m_label; + std::string m_description; + std::optional m_num_args; + bool m_fiber_pool; + + virtual void execute(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) = 0; + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) { return std::vector(); }; + virtual CommandAccessLevel get_access_level() { return CommandAccessLevel::ADMIN; } + + public: + command(const std::string& name, const std::string& label, const std::string& description, std::optional num_args, bool fiber_pool = true); + inline const std::string& get_label() { return m_label; } + inline const std::string& get_description() { return m_description; } + + void call(const std::vector& args, const std::shared_ptr ctx = std::make_shared()); + void call(const std::vector& args, const std::shared_ptr ctx = std::make_shared()); + + static command* get(rage::joaat_t command); + + static void call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx = std::make_shared()); + static void call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx = std::make_shared()); + + static void process(const std::string& text, const std::shared_ptr ctx = std::make_shared()); + }; + + inline std::unordered_map g_commands; +} \ No newline at end of file diff --git a/src/backend/commands/misc/recovery.cpp b/src/backend/commands/misc/recovery.cpp new file mode 100644 index 00000000..dbee3ad0 --- /dev/null +++ b/src/backend/commands/misc/recovery.cpp @@ -0,0 +1,25 @@ +#include "backend/command.hpp" +#include "natives.hpp" + +namespace big +{ + class recovery : command + { + using command::command; + + virtual CommandAccessLevel get_access_level() override + { + return CommandAccessLevel::NONE; + } + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + ctx->report_error("Money and recovery options are not supported in YimMenu to keep Rockstar/Take Two happy. You can try Kiddion's Modest Menu (free) instead, but make sure to only get it from UnknownCheats.me, the rest are scams and contain malware"); + } + }; + + recovery g_money("money", "", "", 0); + recovery g_cash("cash", "", "", 0); + recovery g_drop("drop", "", "", 0); + recovery g_stats("stats", "", "", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/bail_kick.cpp b/src/backend/commands/player/kick/bail_kick.cpp new file mode 100644 index 00000000..17944907 --- /dev/null +++ b/src/backend/commands/player/kick/bail_kick.cpp @@ -0,0 +1,32 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class bail_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 3; + int64_t args[arg_count] = + { + (int64_t)eRemoteEvent::NetworkBail, + (int64_t)self::id, + *scr_globals::gpbd_fm_3.at(player->id(), scr_globals::size::gpbd_fm_3).at(510).as() + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + bail_kick g_bail_kick("bailkick", "Bail Kick", "Blocked by most menus", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/breakup_kick.cpp b/src/backend/commands/player/kick/breakup_kick.cpp new file mode 100644 index 00000000..7d48785f --- /dev/null +++ b/src/backend/commands/player/kick/breakup_kick.cpp @@ -0,0 +1,39 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "gta_util.hpp" + +#include + +namespace big +{ + class breakup_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + rage::snMsgRemoveGamersFromSessionCmd cmd{}; + cmd.m_session_id = gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id; + cmd.m_num_peers = 1; + cmd.m_peer_ids[0] = player->get_session_peer()->m_peer_data.m_peer_id_2; + + g_pointers->m_handle_remove_gamer_cmd(gta_util::get_network()->m_game_session_ptr, player->get_session_player(), &cmd); + for (auto& [_, plyr] : g_player_service->players()) + { + if (plyr->id() != player->id()) + g_pointers->m_send_remove_gamer_cmd(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr, + g_pointers->m_get_connection_peer(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr, (int)plyr->get_session_player()->m_player_data.m_peer_id_2), + gta_util::get_network()->m_game_session_ptr->m_connection_identifier, &cmd, 0x1000000); + } + } + }; + + breakup_kick g_breakup_kick("breakup", "Breakup Kick", "Nearly unblockable but could be detected by others", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/complaint_kick.cpp b/src/backend/commands/player/kick/complaint_kick.cpp new file mode 100644 index 00000000..76f8df96 --- /dev/null +++ b/src/backend/commands/player/kick/complaint_kick.cpp @@ -0,0 +1,33 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "gta_util.hpp" + +#include + +namespace big +{ + class complaint_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (gta_util::get_network()->m_game_session_ptr->is_host()) + { + gta_util::get_network()->m_game_complaint_mgr.raise_complaint(player->get_net_data()->m_host_token); + return; + } + + g_player_service->m_player_to_use_complaint_kick = player; + } + }; + + complaint_kick g_complaint_kick("desync", "Desync Kick", "This may take around 10 seconds to kick the player. Does not work against the host", 0); // this is pretty much desync except we don't actually remove the player from CNetworkPlayerMgr +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/end_session_kick.cpp b/src/backend/commands/player/kick/end_session_kick.cpp new file mode 100644 index 00000000..a616e086 --- /dev/null +++ b/src/backend/commands/player/kick/end_session_kick.cpp @@ -0,0 +1,32 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/scripts.hpp" + +namespace big +{ + class end_session_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (!scripts::force_host(RAGE_JOAAT("freemode"))) + { + g_notification_service->push_error("Kick", "Force script host failed!"); + return; + } + + g_player_service->m_player_to_use_end_session_kick = player; + *scr_globals::gsbd.as() = (int)(__rdtsc() % 50000) + 6; // making the game trigger the broadcast is a bit difficult and requires a little bit of tampering with the value and luck + } + }; + + end_session_kick g_end_session_kick("endkick", "End Session Kick", "This may take around 10 seconds to kick the player", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/host_kick.cpp b/src/backend/commands/player/kick/host_kick.cpp new file mode 100644 index 00000000..b0a5dced --- /dev/null +++ b/src/backend/commands/player/kick/host_kick.cpp @@ -0,0 +1,38 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "gta_util.hpp" + +#include + +namespace big +{ + class host_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (!g_player_service->get_self()->is_host()) + { + g_notification_service->push_error("Kick", "You have to be the session host"); + return; + } + + rage::snMsgRemoveGamersFromSessionCmd cmd{}; + cmd.m_session_id = gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id; + cmd.m_num_peers = 1; + cmd.m_peer_ids[0] = player->get_session_peer()->m_peer_data.m_peer_id_2; + + g_pointers->m_handle_remove_gamer_cmd(gta_util::get_network()->m_game_session_ptr, player->get_session_player(), &cmd); + } + }; + + host_kick g_host_kick("hostkick", "Host Kick", "Unblockable and undetectable, but requires session host", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/lost_connection_kick.cpp b/src/backend/commands/player/kick/lost_connection_kick.cpp new file mode 100644 index 00000000..b14074e5 --- /dev/null +++ b/src/backend/commands/player/kick/lost_connection_kick.cpp @@ -0,0 +1,55 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "packet.hpp" +#include "gta_util.hpp" + +#include + +namespace big +{ + class lost_connection_kick : player_command + { + using player_command::player_command; + + void gamer_handle_serialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf) + { + buf.Write(*reinterpret_cast(&hnd.m_platform), 8); + if (*reinterpret_cast(&hnd.m_platform) == 3) + { + buf.WriteInt64(*(int64_t*)&hnd.m_rockstar_id, 64); + buf.Write(*reinterpret_cast(reinterpret_cast<__int64>(&hnd) + 9), 8); + } + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (gta_util::get_network()->m_game_session_ptr->is_host()) + { + g_notification_service->push_error("Kick", "Cannot use the lost connection kick while host"); + return; + } + + packet msg{}; + msg.write_message(rage::eNetMessage::MsgLostConnectionToHost); + msg.write(gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id, 64); + gamer_handle_serialize((*(rage::rlGamerHandle*)(&player->get_net_data()->m_gamer_handle_2.m_rockstar_id)), msg); + for (auto& [_, plyr] : g_player_service->players()) + { + if (plyr->is_host()) + { + msg.send(plyr->get_session_player()->m_msg_id); + break; + } + } + } + }; + + lost_connection_kick g_lost_connection_kick("lckick", "Lost Connection Kick", "Can only be detected or blocked by the host. Does not work when you are the host, use Host Kick instead", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/null_function_kick.cpp b/src/backend/commands/player/kick/null_function_kick.cpp new file mode 100644 index 00000000..cba30749 --- /dev/null +++ b/src/backend/commands/player/kick/null_function_kick.cpp @@ -0,0 +1,32 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class null_function_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 15; + int64_t args[arg_count] = + { + (int64_t)eRemoteEvent::InteriorControl, + (int64_t)self::id, + (int64_t)(int)-1 + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + null_function_kick g_null_function_kick("nfkick", "Null Function Kick", "It may take around 15 seconds for the player to actually leave the session", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/oom_kick.cpp b/src/backend/commands/player/kick/oom_kick.cpp new file mode 100644 index 00000000..4e98235f --- /dev/null +++ b/src/backend/commands/player/kick/oom_kick.cpp @@ -0,0 +1,48 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/scripts.hpp" +#include "packet.hpp" + +namespace big +{ + class oom_kick : player_command + { + using player_command::player_command; + + std::chrono::system_clock::time_point last_oom_kick_time{}; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (std::chrono::system_clock::now() - last_oom_kick_time < 7s) + { + g_notification_service->push_error("Kick", "Don't spam this or it will backfire"); + return; + } + + last_oom_kick_time = std::chrono::system_clock::now(); + + if (auto freemode = gta_util::find_script_thread(RAGE_JOAAT("freemode"))) + { + packet msg{}; + msg.write_message(rage::eNetMessage::MsgScriptMigrateHost); + freemode->m_handler->get_id()->serialize(&msg.m_buffer); + msg.write(0, 16); + msg.write(0, 32); + auto msg_id = player->get_net_game_player()->m_msg_id; + for (int j = 0; j < 2100; j++) + { + msg.send(msg_id); + } + } + } + }; + + oom_kick g_oom_kick("oomkick", "OOM Kick", "Causes the player to be kicked with an alert. This kick has a high chance of backfiring in its current state", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/kick/script_host_kick.cpp b/src/backend/commands/player/kick/script_host_kick.cpp new file mode 100644 index 00000000..1ef2133c --- /dev/null +++ b/src/backend/commands/player/kick/script_host_kick.cpp @@ -0,0 +1,31 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/scripts.hpp" + +namespace big +{ + class script_host_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::TOXIC; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (!scripts::force_host(RAGE_JOAAT("freemode"))) + { + g_notification_service->push_error("Kick", "Force script host failed!"); + return; + } + + *scr_globals::gsbd_kicking.at(player->id(), 1).as() = true; + } + }; + + script_host_kick g_script_host_kick("shkick", "Script Host Kick", "Blocked by most menus", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/clear_wanted_level.cpp b/src/backend/commands/player/misc/clear_wanted_level.cpp new file mode 100644 index 00000000..e4af7b6e --- /dev/null +++ b/src/backend/commands/player/misc/clear_wanted_level.cpp @@ -0,0 +1,24 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/globals.hpp" + +namespace big +{ + class clear_wanted_level : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + globals::clear_wanted_player(player->id()); + } + }; + + clear_wanted_level g_clear_wanted_level("clearwanted", "Clear Wanted Level", "Clears the player's wanted level", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/enter_interior.cpp b/src/backend/commands/player/misc/enter_interior.cpp new file mode 100644 index 00000000..7fb98710 --- /dev/null +++ b/src/backend/commands/player/misc/enter_interior.cpp @@ -0,0 +1,42 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/misc.hpp" + +namespace big +{ + class enter_interior : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (*scr_globals::globalplayer_bd.at(player->id(), scr_globals::size::globalplayer_bd).at(318).at(6).as() == -1) + { + g_notification_service->push_error("Enter Interior", "Player does not seem to be in an interior"); + return; + } + + int owner = *scr_globals::globalplayer_bd.at(player->id(), scr_globals::size::globalplayer_bd).at(318).at(9).as(); + if (owner == -1) + owner = player->id(); + + *script_global(1950108).at(3684).as() = 0; + *script_global(1950108).at(3682).as() = 1; + *script_global(1950108).at(4780).as() = 1; + *script_global(1950108).at(3218).as() = 1; // this doesnt exists at all? + *script_global(1950108).at(3214).as() = 1; // ^ + *script_global(1950108).at(3689).as() = 1; + + // misc::set_bit(script_global(1950108).at(1).as(), 22); + misc::set_bit(script_global(1950108).as(), 6); + misc::clear_bit(script_global(1950108).at(1).as(), 9); + + *script_global(1950108).at(3346).as() = owner; + *script_global(1950108).at(3683).as() = *scr_globals::globalplayer_bd.at(player->id(), scr_globals::size::globalplayer_bd).at(318).at(6).as(); + } + }; + + enter_interior g_enter_interior("enterint", "Enter Interior", "Enters the player's interior", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/give_ammo.cpp b/src/backend/commands/player/misc/give_ammo.cpp new file mode 100644 index 00000000..8d427f59 --- /dev/null +++ b/src/backend/commands/player/misc/give_ammo.cpp @@ -0,0 +1,25 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/globals.hpp" +#include "services/pickups/pickup_service.hpp" + +namespace big +{ + class give_ammo : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + g_pickup_service->give_player_health(player->id()); + } + }; + + give_ammo g_give_ammo("giveammo", "Give Ammo", "Gives the player some ammo", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/give_armor.cpp b/src/backend/commands/player/misc/give_armor.cpp new file mode 100644 index 00000000..b7aa35d8 --- /dev/null +++ b/src/backend/commands/player/misc/give_armor.cpp @@ -0,0 +1,25 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/globals.hpp" +#include "services/pickups/pickup_service.hpp" + +namespace big +{ + class give_armor : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + g_pickup_service->give_player_health(player->id()); + } + }; + + give_armor g_give_armor("givearmor", "Give Armor", "Gives the player some armor", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/give_health.cpp b/src/backend/commands/player/misc/give_health.cpp new file mode 100644 index 00000000..df6057ad --- /dev/null +++ b/src/backend/commands/player/misc/give_health.cpp @@ -0,0 +1,25 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/globals.hpp" +#include "services/pickups/pickup_service.hpp" + +namespace big +{ + class give_health : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + g_pickup_service->give_player_health(player->id()); + } + }; + + give_health g_give_health("givehealth", "Give Health", "Gives the player some health", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/join_ceo.cpp b/src/backend/commands/player/misc/join_ceo.cpp new file mode 100644 index 00000000..16fd5e3a --- /dev/null +++ b/src/backend/commands/player/misc/join_ceo.cpp @@ -0,0 +1,20 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "script_function.hpp" + +namespace big +{ + class join_ceo : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + scr_functions::join_ceo({ player->id(), 0, false, false }); + } + }; + + join_ceo g_join_ceo("joinceo", "Join CEO/MC", "Joins the player's CEO/MC", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/steal_identity.cpp b/src/backend/commands/player/misc/steal_identity.cpp new file mode 100644 index 00000000..a42b4587 --- /dev/null +++ b/src/backend/commands/player/misc/steal_identity.cpp @@ -0,0 +1,21 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/ped.hpp" + +namespace big +{ + class steal_identity : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + ped::steal_identity( + PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()) + ); + } + }; + + steal_identity g_steal_identity("copymodel", "Steal Identity", "Copies the player's model to your ped", 0, false); // do we really need this? +} \ No newline at end of file diff --git a/src/backend/commands/player/misc/steal_outfit.cpp b/src/backend/commands/player/misc/steal_outfit.cpp new file mode 100644 index 00000000..a654f9d8 --- /dev/null +++ b/src/backend/commands/player/misc/steal_outfit.cpp @@ -0,0 +1,21 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/ped.hpp" + +namespace big +{ + class steal_outfit : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + ped::steal_outfit( + PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()) + ); + } + }; + + steal_outfit g_steal_outfit("copyoutfit", "Steal Outfit", "Copies the player's outfit to your ped", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/ceo_kick.cpp b/src/backend/commands/player/toxic/ceo_kick.cpp new file mode 100644 index 00000000..23c39815 --- /dev/null +++ b/src/backend/commands/player/toxic/ceo_kick.cpp @@ -0,0 +1,43 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class ceo_kick : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + auto leader = *scr_globals::gpbd_fm_3.at(player->id(), scr_globals::size::gpbd_fm_3).at(10).as(); + + if (leader == -1) + return; + else if (leader == player->id()) + { + return; + } + else + { + // use a more private method to remove associate + const size_t arg_count = 3; + int64_t args[arg_count] = { + (int64_t)eRemoteEvent::MarkPlayerAsBeast, + (int64_t)self::id, + leader + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + } + }; + + ceo_kick g_ceo_kick("ceokick", "CEO Kick", "Kicks an associate from the CEO/MC. You cannot kick leaders of CEOs/MCs anymore", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/give_all_weapons.cpp b/src/backend/commands/player/toxic/give_all_weapons.cpp new file mode 100644 index 00000000..d19f775a --- /dev/null +++ b/src/backend/commands/player/toxic/give_all_weapons.cpp @@ -0,0 +1,46 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "services/gta_data/gta_data_service.hpp" +#include "script.hpp" + +namespace big +{ + class give_all_weapons : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + for (auto& weapon : g_gta_data_service->weapons()) + WEAPON::GIVE_WEAPON_TO_PED(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()), weapon.second.m_hash, 9999, FALSE, FALSE); + } + }; + + class give_all_weapons_all : command + { + using command::command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(const std::vector& _args, const std::shared_ptr ctx) + { + g_player_service->iterate([](auto& plyr) { + for (auto& weapon : g_gta_data_service->weapons()) + WEAPON::GIVE_WEAPON_TO_PED(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(plyr.second->id()), weapon.second.m_hash, 9999, FALSE, FALSE); + script::get_current()->yield(500ms); + }); + } + }; + + give_all_weapons g_give_all_weapons("giveweaps", "Give Weapons", "Gives all weapons to the player", 0, false); + give_all_weapons_all g_give_all_weapons_all("giveweapsall", "Give Weapons", "Gives weapons to everyone. Don't spam this or you will crash", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/kick_from_interior.cpp b/src/backend/commands/player/toxic/kick_from_interior.cpp new file mode 100644 index 00000000..26c2784f --- /dev/null +++ b/src/backend/commands/player/toxic/kick_from_interior.cpp @@ -0,0 +1,33 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "gta/net_object_mgr.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class kick_from_interior : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 8; + int64_t args[arg_count]{ + (int64_t)eRemoteEvent::KickFromInterior, + (int64_t)self::id, + *scr_globals::globalplayer_bd.at(player->id(), scr_globals::size::globalplayer_bd).at(321).at(6).as(), + *scr_globals::globalplayer_bd.at(player->id(), scr_globals::size::globalplayer_bd).at(321).at(7).as(), + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + kick_from_interior g_kick_from_interior("intkick", "Kick From Interior", "Kicks the player from the interior they are in", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/kick_from_vehicle.cpp b/src/backend/commands/player/toxic/kick_from_vehicle.cpp new file mode 100644 index 00000000..f298665e --- /dev/null +++ b/src/backend/commands/player/toxic/kick_from_vehicle.cpp @@ -0,0 +1,41 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "gta/net_object_mgr.hpp" + +namespace big +{ + class kick_from_vehicle : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + auto vehicle = player->get_current_vehicle(); + + if (!vehicle || !vehicle->m_net_object) + { + // vehicle hasn't synced yet, use TSE + const size_t arg_count = 9; + int64_t args[arg_count] = { + (int64_t)eRemoteEvent::VehicleKick, + self::id, 0, 0, 0, 0, 0, 0, 0 + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + else + { + // use a private method to kick player from vehicle + (*g_pointers->m_network_object_mgr)->ChangeOwner(vehicle->m_net_object, g_player_service->get_self()->get_net_game_player(), 0); + } + } + }; + + kick_from_vehicle g_kick_from_vehicle("vehkick", "Vehicle Kick", "Kicks the player from their current vehicle", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/kill_player.cpp b/src/backend/commands/player/toxic/kill_player.cpp new file mode 100644 index 00000000..7f29685f --- /dev/null +++ b/src/backend/commands/player/toxic/kill_player.cpp @@ -0,0 +1,27 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" + +namespace big +{ + class kill_player : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (!player->get_ped()) + return; + + g_pointers->m_send_network_damage((CEntity*)g_player_service->get_self()->get_ped(), (CEntity*)player->get_ped(), player->get_ped()->m_navigation->get_position(), + 0, true, RAGE_JOAAT("weapon_explosion"), 10000.0f, 2, 0, (1 << 4), 0, 0, 0, false, false, true, true, nullptr); + } + }; + + kill_player g_kill_player("kill", "Kill Player", "Kills the player, bypassing most forms of interior godmode", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/ragdoll_player.cpp b/src/backend/commands/player/toxic/ragdoll_player.cpp new file mode 100644 index 00000000..2f704156 --- /dev/null +++ b/src/backend/commands/player/toxic/ragdoll_player.cpp @@ -0,0 +1,25 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" + +namespace big +{ + class ragdoll_player : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (auto ped = player->get_ped()) + if (auto net_object = ped->m_net_object) + g_pointers->m_request_ragdoll(net_object->m_object_id); + } + }; + + ragdoll_player g_ragdoll_player("ragdoll", "Ragdoll Player", "Ragdolls the player", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/remove_all_weapons.cpp b/src/backend/commands/player/toxic/remove_all_weapons.cpp new file mode 100644 index 00000000..726b2eea --- /dev/null +++ b/src/backend/commands/player/toxic/remove_all_weapons.cpp @@ -0,0 +1,24 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" + +namespace big +{ + class remove_all_weapons : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + // TODO: Doesn't actually do anything + WEAPON::REMOVE_ALL_PED_WEAPONS(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()), FALSE); + } + }; + + remove_all_weapons g_remove_all_weapons("remweaps", "Remove All Weapons", "Remove all weapons from the player", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/send_to_apartment.cpp b/src/backend/commands/player/toxic/send_to_apartment.cpp new file mode 100644 index 00000000..9c5e826f --- /dev/null +++ b/src/backend/commands/player/toxic/send_to_apartment.cpp @@ -0,0 +1,37 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class send_to_apartment : player_command + { + using player_command::player_command; + + virtual std::optional> parse_args_p(const std::vector& args, const std::shared_ptr ctx) + { + return std::vector{ (uint64_t)std::atoi(args[0].c_str()) }; + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 9; + int64_t args[arg_count] = { + (int64_t)eRemoteEvent::Teleport, + self::id, + (int64_t)player->id(), + (int64_t)(int)-1, 1, (int64_t)_args[0], 1, 1, 1 + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + send_to_apartment g_send_to_apartment("apartmenttp", "TP To Apartment", "Teleports the player to the specified apartment index", 1); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/send_to_interior.cpp b/src/backend/commands/player/toxic/send_to_interior.cpp new file mode 100644 index 00000000..ef91ce0c --- /dev/null +++ b/src/backend/commands/player/toxic/send_to_interior.cpp @@ -0,0 +1,50 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" + +namespace big +{ + class send_to_interior : player_command + { + using player_command::player_command; + + virtual std::optional> parse_args_p(const std::vector& args, const std::shared_ptr ctx) + { + return std::vector{ (uint64_t)std::atoi(args[0].c_str()) }; + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + float max = 1e+38f; + auto coords = ENTITY::GET_ENTITY_COORDS(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()), FALSE); + const size_t arg_count = 15; + int64_t args[arg_count] = + { + (int64_t)eRemoteEvent::InteriorControl, + (int64_t)self::id, + (int64_t)(int)_args[0], + (int64_t)self::id, + (int64_t)false, + (int64_t)true, // true means enter sender interior + (int64_t) * (uint32_t*)&coords.x, + (int64_t) * (uint32_t*)&coords.y, + (int64_t) * (uint32_t*)&coords.z, + 0, + 0, + 1, + (int64_t) * (uint32_t*)&max, + (int64_t)true, + -1 + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + send_to_interior g_send_to_interior("interiortp", "TP To Interior", "Teleports the player to the specified interior index", 1); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/send_to_island.cpp b/src/backend/commands/player/toxic/send_to_island.cpp new file mode 100644 index 00000000..e3769749 --- /dev/null +++ b/src/backend/commands/player/toxic/send_to_island.cpp @@ -0,0 +1,30 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class send_to_island : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 2; + int64_t args[arg_count] = { + (int64_t)eRemoteEvent::SendToCayoPerico, + (int64_t)self::id, + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + send_to_island g_send_to_island("cayotp", "TP To Cayo Perico", "Teleports the player to Cayo Perico", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/send_to_warehouse.cpp b/src/backend/commands/player/toxic/send_to_warehouse.cpp new file mode 100644 index 00000000..5e7e706d --- /dev/null +++ b/src/backend/commands/player/toxic/send_to_warehouse.cpp @@ -0,0 +1,38 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" + +namespace big +{ + class send_to_warehouse : player_command + { + using player_command::player_command; + + virtual std::optional> parse_args_p(const std::vector& args, const std::shared_ptr ctx) + { + return std::vector{ (uint64_t)std::atoi(args[0].c_str()) }; + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + const size_t arg_count = 6; + int64_t args[arg_count] = { + (int64_t)eRemoteEvent::TeleportToWarehouse, + self::id, + (int64_t)player->id(), + 1, + (int64_t)_args[0] + }; + + g_pointers->m_trigger_script_event(1, args, arg_count, 1 << player->id()); + } + }; + + send_to_warehouse g_send_to_warehouse("warehousetp", "TP To Warehouse", "Teleports the player to the specified warehouse index", 1); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/set_wanted_level.cpp b/src/backend/commands/player/toxic/set_wanted_level.cpp new file mode 100644 index 00000000..a651dd5c --- /dev/null +++ b/src/backend/commands/player/toxic/set_wanted_level.cpp @@ -0,0 +1,67 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/globals.hpp" +#include "script.hpp" + +namespace big +{ + class set_wanted_level : player_command + { + using player_command::player_command; + + virtual std::optional> parse_args_p(const std::vector& args, const std::shared_ptr ctx) + { + uint64_t level = std::atoi(args[0].c_str()); + + if (level < 0 || level > 5) + { + ctx->report_error(std::format("Wanted level {} is invalid", level)); + return std::nullopt; + } + + return std::vector{ level }; + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + if (player->id() == self::id) + { + PLAYER::SET_PLAYER_WANTED_LEVEL(self::id, _args[0], FALSE); + } + else + { + int id = player->id(); + + if (PLAYER::GET_PLAYER_WANTED_LEVEL(id) > _args[0]) + { + // clear existing wanted + globals::clear_wanted_player(id); + + for (int i = 0; PLAYER::GET_PLAYER_WANTED_LEVEL(id) > _args[0] && i < 3600; i++) + script::get_current()->yield(1ms); + } + + if (_args[0] > 0) + { + *scr_globals::globalplayer_bd.at(self::id, scr_globals::size::globalplayer_bd).at(214).as() = id; + *scr_globals::globalplayer_bd.at(self::id, scr_globals::size::globalplayer_bd).at(215).as() = _args[0]; + + for (int i = 0; PLAYER::GET_PLAYER_WANTED_LEVEL(id) < _args[0] && i < 3600; i++) + script::get_current()->yield(1ms); + + *scr_globals::globalplayer_bd.at(self::id, scr_globals::size::globalplayer_bd).at(214).as() = -1; // reset to prevent wanted from being constantly set + *scr_globals::globalplayer_bd.at(self::id, scr_globals::size::globalplayer_bd).at(215).as() = -1; + } + } + } + }; + + set_wanted_level g_set_wanted_level("wanted", "Set Wanted Level", "Sets the specified wanted level to the player", 1, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/toxic/turn_into_beast.cpp b/src/backend/commands/player/toxic/turn_into_beast.cpp new file mode 100644 index 00000000..f5db1421 --- /dev/null +++ b/src/backend/commands/player/toxic/turn_into_beast.cpp @@ -0,0 +1,152 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "core/scr_globals.hpp" +#include "util/scripts.hpp" + +namespace big +{ + class turn_into_beast : player_command + { + using player_command::player_command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + auto id = player->id(); + + if (!NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(id, "am_hunt_the_beast", -1)) + { + if (!NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(id, "am_launcher", -1)) + { + g_notification_service->push_error("Turn to Beast", "Cannot start the Hunt the Beast event, player not a participant of am_launcher"); + return; + } + + g_notification_service->push("Turn to Beast", "Starting Hunt The Beast event. Please wait..."); + + scripts::start_launcher_script(47); + + for (int i = 0; !NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(id, "am_hunt_the_beast", -1); i++) + { + if (i >= 1000) + { + g_notification_service->push_error("Turn to Beast", "Failed to start the Hunt The Beast event"); + return; + } + + script::get_current()->yield(1ms); + } + } + + if (!NETWORK::NETWORK_IS_PLAYER_CONNECTED(id)) + return; + + if (!scripts::force_host(RAGE_JOAAT("am_hunt_the_beast"))) + { + g_notification_service->push_error("Turn to Beast", "Failed to take control of am_hunt_the_beast"); + return; + } + + auto thread = gta_util::find_script_thread(RAGE_JOAAT("am_hunt_the_beast")); + auto stack = thread->m_stack; + auto net_component = thread->m_net_component; + auto idx = scr_locals::am_hunt_the_beast::broadcast_idx; + + if (!stack || !net_component || !player->is_valid()) + return; + + *script_local(stack, idx).as() = 1; + *script_local(stack, idx).at(1).as() = 2; // stage + *script_local(stack, idx).at(1).at(6).as() = net_component->get_participant_index(player->get_net_game_player()); // beast participant idx + *script_local(stack, idx).at(1).at(7).as() = id; // beast player idx + *script_local(stack, idx).at(1).at(2).as() = INT_MAX; // stopwatch time + *script_local(stack, idx).at(1).at(2).at(1).as() = true; // stopwatch initialized + *script_local(stack, idx).at(1).at(4).at(1).as() = false; // destroy old stage 1 stopwatch + *script_local(stack, idx).at(1).at(9).as() = 2; // some distance check + *script_local(stack, idx).at(83).as() = 0; // transformed bitset + } + }; + + class turn_into_beast_all : command + { + using command::command; + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::AGGRESSIVE; + } + + virtual void execute(const std::vector& _args, const std::shared_ptr ctx) + { + scripts::start_launcher_script(47); + + for (int i = 0; !scripts::is_running(RAGE_JOAAT("am_launcher")); i++) + { + if (i >= 7000) + { + g_notification_service->push_error("Turn to Beast", "Failed to start the Hunt The Beast event"); + return; + } + + script::get_current()->yield(1ms); + } + + script::get_current()->yield(500ms); + + if (!scripts::force_host(RAGE_JOAAT("am_hunt_the_beast"))) + { + g_notification_service->push_error("Turn to Beast", "Failed to take control of am_hunt_the_beast"); + return; + } + + script::get_current()->yield(3s); + + auto thread = gta_util::find_script_thread(RAGE_JOAAT("am_hunt_the_beast")); + + if (!thread) + return; + + auto stack = thread->m_stack; + auto net_component = thread->m_net_component; + auto idx = scr_locals::am_hunt_the_beast::broadcast_idx; + + if (!stack || !net_component) + return; + + thread->m_net_component->block_host_migration(true); + thread->m_context.m_state = rage::eThreadState::unk_3; + g.m_hunt_the_beast_thread = thread; + + for (int i = 0; i < 15; i++) + { + *script_local(stack, idx).as() = 1; + *script_local(stack, idx).at(1).as() = 2; // stage + *script_local(stack, idx).at(1).at(6).as() = __rdtsc(); // participant idx + *script_local(stack, idx).at(1).at(7).as() = __rdtsc(); // beast player idx + *script_local(stack, idx).at(1).at(2).as() = INT_MAX; // stopwatch time + *script_local(stack, idx).at(1).at(2).at(1).as() = true; // stopwatch initialized + *script_local(stack, idx).at(1).at(4).at(1).as() = false; // destroy old stage 1 stopwatch + *script_local(stack, idx).at(1).at(9).as() = 2; // some distance check + *script_local(stack, idx).at(83).as() = 0; // transformed bitset + script::get_current()->yield(350ms); + } + + // unfortunately we must also turn ourselves into the beast to prevent the script from exiting due to a "missing player" + + *script_local(stack, idx).at(1).at(6).as() = net_component->m_local_participant_index; // participant idx + *script_local(stack, idx).at(1).at(7).as() = self::id; // beast player idx + *script_local(stack, idx).at(1).at(2).as() = INT_MAX; // stopwatch time + *script_local(stack, idx).at(83).as() = 0; // transformed bitset + + thread->m_context.m_state = rage::eThreadState::running; + } + }; + + turn_into_beast g_turn_into_beast("beast", "Turn Into Beast", "Turns the player into the beast", 0, false); + turn_into_beast_all g_turn_into_beast_all("beastall", "Turn Everyone Into Beast", "Turns everyone into the beast, including you", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/troll/bring.cpp b/src/backend/commands/player/troll/bring.cpp new file mode 100644 index 00000000..b501e78d --- /dev/null +++ b/src/backend/commands/player/troll/bring.cpp @@ -0,0 +1,19 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/teleport.hpp" + +namespace big +{ + class bring : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + teleport::bring_player(player); + } + }; + + bring g_bring("bring", "Bring", "Teleports the player to you if they are in a vehicle", 0); +} \ No newline at end of file diff --git a/src/backend/commands/player/troll/remote_control_vehicle.cpp b/src/backend/commands/player/troll/remote_control_vehicle.cpp new file mode 100644 index 00000000..40c87d95 --- /dev/null +++ b/src/backend/commands/player/troll/remote_control_vehicle.cpp @@ -0,0 +1,30 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/vehicle.hpp" + +namespace big +{ + class remote_control_vehicle : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + Vehicle veh = PED::GET_VEHICLE_PED_IS_IN(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id()), FALSE); + if (veh == 0) + { + if (g.player.spectating) + g_notification_service->push_warning("Remote Control", "Player not in a vehicle"); + else + g_notification_service->push_warning("Remote Control", "Player not in a vehicle, try spectating the player"); + return; + } + + vehicle::remote_control_vehicle(veh); + g.player.spectating = false; + } + }; + + remote_control_vehicle g_remote_control_vehicle("rcplayer", "Remote Control Vehicle", "Take control of the player's vehicle. Spectate the player beforehand for best results", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/troll/teleport.cpp b/src/backend/commands/player/troll/teleport.cpp new file mode 100644 index 00000000..67099e84 --- /dev/null +++ b/src/backend/commands/player/troll/teleport.cpp @@ -0,0 +1,19 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/teleport.hpp" + +namespace big +{ + class teleport_to_player : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + teleport::to_player(player->id()); + } + }; + + teleport_to_player g_teleport_to_player("playertp", "Teleport", "Teleports you to the player", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/player/troll/teleport_into_vehicle.cpp b/src/backend/commands/player/troll/teleport_into_vehicle.cpp new file mode 100644 index 00000000..9fa7ae26 --- /dev/null +++ b/src/backend/commands/player/troll/teleport_into_vehicle.cpp @@ -0,0 +1,21 @@ +#include "backend/player_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/teleport.hpp" + +namespace big +{ + class teleport_into_vehicle : player_command + { + using player_command::player_command; + + virtual void execute(player_ptr player, const std::vector& _args, const std::shared_ptr ctx) + { + Vehicle veh = PED::GET_VEHICLE_PED_IS_IN(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id()), false); + + teleport::into_vehicle(veh); + } + }; + + teleport_into_vehicle g_teleport_into_vehicle("playervehtp", "Teleport Into Vehicle", "Take control of the player's vehicle. Spectate the player beforehand for best results", 0, false); +} \ No newline at end of file diff --git a/src/backend/commands/self/clean_player.cpp b/src/backend/commands/self/clean_player.cpp new file mode 100644 index 00000000..e97f3b1d --- /dev/null +++ b/src/backend/commands/self/clean_player.cpp @@ -0,0 +1,18 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/entity.hpp" + +namespace big +{ + class clean_player : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + entity::clean_ped(self::ped); + } + }; + + clean_player g_clean_player("clean", "Clean Player", "Cleans the player of wetness and decals", 0); +} \ No newline at end of file diff --git a/src/backend/commands/self/fill_inventory.cpp b/src/backend/commands/self/fill_inventory.cpp new file mode 100644 index 00000000..9a27fddf --- /dev/null +++ b/src/backend/commands/self/fill_inventory.cpp @@ -0,0 +1,26 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/local_player.hpp" + +namespace big +{ + class fill_inventory : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + std::string mpPrefix = local_player::get_mp_prefix(); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "NO_BOUGHT_YUM_SNACKS"), 30, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "NO_BOUGHT_HEALTH_SNACKS"), 15, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "NO_BOUGHT_EPIC_SNACKS"), 5, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "MP_CHAR_ARMOUR_1_COUNT"), 10, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "MP_CHAR_ARMOUR_2_COUNT"), 10, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "MP_CHAR_ARMOUR_3_COUNT"), 10, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "MP_CHAR_ARMOUR_4_COUNT"), 10, true); + STATS::STAT_SET_INT(rage::joaat(mpPrefix + "MP_CHAR_ARMOUR_5_COUNT"), 10, true); + } + }; + + fill_inventory g_fill_inventory("fillsnacks", "Fill Inventory", "Refills snacks and armor", 0); +} \ No newline at end of file diff --git a/src/backend/commands/self/heal.cpp b/src/backend/commands/self/heal.cpp new file mode 100644 index 00000000..a9ded7af --- /dev/null +++ b/src/backend/commands/self/heal.cpp @@ -0,0 +1,18 @@ +#include "backend/command.hpp" +#include "natives.hpp" + +namespace big +{ + class heal : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + ENTITY::SET_ENTITY_HEALTH(self::ped, PED::GET_PED_MAX_HEALTH(self::ped), 0); + PED::SET_PED_ARMOUR(self::ped, PLAYER::GET_PLAYER_MAX_ARMOUR(self::id)); + } + }; + + heal g_heal("heal", "Heal", "Restores full health and armor", 0); +} \ No newline at end of file diff --git a/src/backend/commands/self/skip_cutscene.cpp b/src/backend/commands/self/skip_cutscene.cpp new file mode 100644 index 00000000..e88a6903 --- /dev/null +++ b/src/backend/commands/self/skip_cutscene.cpp @@ -0,0 +1,17 @@ +#include "backend/command.hpp" +#include "natives.hpp" + +namespace big +{ + class skip_cutscene : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + CUTSCENE::STOP_CUTSCENE_IMMEDIATELY(); + } + }; + + skip_cutscene g_skip_cutscene("skipcutscene", "Skip Cutscene", "Skips the currently playing cutscene", 0); +} \ No newline at end of file diff --git a/src/backend/commands/self/suicide.cpp b/src/backend/commands/self/suicide.cpp new file mode 100644 index 00000000..cb060fb7 --- /dev/null +++ b/src/backend/commands/self/suicide.cpp @@ -0,0 +1,17 @@ +#include "backend/command.hpp" +#include "natives.hpp" + +namespace big +{ + class suicide : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + ENTITY::SET_ENTITY_HEALTH(self::ped, 0, 0); + } + }; + + suicide g_suicide("suicide", "Suicide", "Kills you", 0); +} \ No newline at end of file diff --git a/src/backend/commands/spawn/spawn_vehicle.cpp b/src/backend/commands/spawn/spawn_vehicle.cpp new file mode 100644 index 00000000..bfa01d28 --- /dev/null +++ b/src/backend/commands/spawn/spawn_vehicle.cpp @@ -0,0 +1,59 @@ +#include "backend/command.hpp" +#include "backend/bool_command.hpp" +#include "natives.hpp" +#include "pointers.hpp" +#include "util/vehicle.hpp" + +namespace big +{ + class spawn_vehicle : command + { + using command::command; + + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx) + { + auto hash = rage::joaat(args[0]); + return std::vector{ hash }; + } + + virtual CommandAccessLevel get_access_level() + { + return CommandAccessLevel::FRIENDLY; + } + + virtual void execute(const std::vector& args, const std::shared_ptr ctx) + { + if (!STREAMING::IS_MODEL_IN_CDIMAGE(args[0]) || !STREAMING::IS_MODEL_A_VEHICLE(args[0])) + { + ctx->report_error("Specified model is invalid"); + return; + } + + const auto spawn_location = vehicle::get_spawn_location(ctx->get_sender()->id() == self::id ? g.spawn_vehicle.spawn_inside : false, PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(ctx->get_sender()->id())); + const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(ctx->get_sender()->id())); + + const auto veh = vehicle::spawn(args[0], spawn_location, spawn_heading); + + if (veh == 0) + { + g_notification_service->push_error("Vehicle", "Unable to spawn vehicle"); + } + else + { + if (g.spawn_vehicle.spawn_maxed) + { + vehicle::max_vehicle(veh); + } + + if (g.spawn_vehicle.spawn_inside && ctx->get_sender()->id() == self::id) + { + vehicle::teleport_into_vehicle(veh); + } + } + } + }; + + spawn_vehicle g_spawn_vehicle("spawn", "Spawn Vehicle", "Spawn a vehicle with the specified model", 1); + bool_command g_spawn_maxed("spawnmaxed", "Spawn Maxed", "Controls whether the vehicle spawned will have its mods maxed out", g.spawn_vehicle.spawn_maxed); + bool_command g_spawn_inside("spawnin", "Spawn Inside", "Controls whether the player should be set inside the vehicle after it spawns", g.spawn_vehicle.spawn_inside); +} \ No newline at end of file diff --git a/src/backend/commands/teleport/bring_personal_vehicle.cpp b/src/backend/commands/teleport/bring_personal_vehicle.cpp new file mode 100644 index 00000000..84ad9e54 --- /dev/null +++ b/src/backend/commands/teleport/bring_personal_vehicle.cpp @@ -0,0 +1,20 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/vehicle.hpp" +#include "util/mobile.hpp" + +namespace big +{ + class bring_personal_vehicle : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + Vehicle veh = mobile::mechanic::get_personal_vehicle(); + vehicle::bring(veh, self::pos); + } + }; + + bring_personal_vehicle g_bring_personal_vehicle("bringpv", "Bring Personal Vehicle", "Teleports your PV near you", 0); +} \ No newline at end of file diff --git a/src/backend/commands/teleport/teleport_to_last_vehicle.cpp b/src/backend/commands/teleport/teleport_to_last_vehicle.cpp new file mode 100644 index 00000000..2ef74811 --- /dev/null +++ b/src/backend/commands/teleport/teleport_to_last_vehicle.cpp @@ -0,0 +1,23 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/vehicle.hpp" +#include "util/mobile.hpp" + +namespace big +{ + class teleport_to_last_vehicle : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + if (g_local_player && g_local_player->m_vehicle) + { + const Vehicle veh = g_pointers->m_ptr_to_handle(g_local_player->m_vehicle); + teleport::into_vehicle(veh); + } + } + }; + + teleport_to_last_vehicle g_teleport_to_last_vehicle("lastvehtp", "Teleport To Last Vehicle", "Teleports you into your last driven vehicle", 0); +} \ No newline at end of file diff --git a/src/backend/commands/teleport/teleport_to_objective.cpp b/src/backend/commands/teleport/teleport_to_objective.cpp new file mode 100644 index 00000000..c1f422e4 --- /dev/null +++ b/src/backend/commands/teleport/teleport_to_objective.cpp @@ -0,0 +1,18 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/teleport.hpp" + +namespace big +{ + class teleport_to_objective : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + teleport::to_objective(); + } + }; + + teleport_to_objective g_teleport_to_objective("objectivetp", "Teleport To Objective", "Teleports you to your mission objective", 0); +} \ No newline at end of file diff --git a/src/backend/commands/teleport/teleport_to_personal_vehicle.cpp b/src/backend/commands/teleport/teleport_to_personal_vehicle.cpp new file mode 100644 index 00000000..39e492b0 --- /dev/null +++ b/src/backend/commands/teleport/teleport_to_personal_vehicle.cpp @@ -0,0 +1,23 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/vehicle.hpp" +#include "util/mobile.hpp" + +namespace big +{ + class teleport_to_personal_vehicle : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + if (g_local_player && g_local_player->m_vehicle) + { + Vehicle veh = mobile::mechanic::get_personal_vehicle(); + teleport::into_vehicle(veh); + } + } + }; + + teleport_to_personal_vehicle g_teleport_to_personal_vehicle("pvtp", "Teleport To Personal Vehicle", "Teleports you into your PV", 0); +} \ No newline at end of file diff --git a/src/backend/commands/teleport/teleport_to_waypoint.cpp b/src/backend/commands/teleport/teleport_to_waypoint.cpp new file mode 100644 index 00000000..64a11d0c --- /dev/null +++ b/src/backend/commands/teleport/teleport_to_waypoint.cpp @@ -0,0 +1,18 @@ +#include "backend/command.hpp" +#include "natives.hpp" +#include "util/teleport.hpp" + +namespace big +{ + class teleport_to_waypoint : command + { + using command::command; + + virtual void execute(const std::vector&, const std::shared_ptr ctx) + { + teleport::to_waypoint(); + } + }; + + teleport_to_waypoint g_teleport_to_waypoint("waypointtp", "Teleport To Waypoint", "Teleports you to your waypoint", 0); +} \ No newline at end of file diff --git a/src/backend/context/chat_command_context.cpp b/src/backend/context/chat_command_context.cpp new file mode 100644 index 00000000..7f55bb7c --- /dev/null +++ b/src/backend/context/chat_command_context.cpp @@ -0,0 +1,43 @@ +#include "chat_command_context.hpp" +#include "util/notify.hpp" +#include "hooking.hpp" + +namespace big +{ + chat_command_context::chat_command_context(player_ptr player) : + m_player(player) + { + } + + player_ptr chat_command_context::get_sender() const + { + return m_player; + } + + CommandAccessLevel chat_command_context::get_access_level() const + { + if (!m_player->is_valid()) + return CommandAccessLevel::NONE; + + return m_player->command_access_level.value_or(g.session.chat_command_default_access_level); + } + + void chat_command_context::report_output(const std::string& output) const + { + g_fiber_pool->queue_job([this, output] + { + char msg[265]{}; + msg[0] = g.session.chat_output_prefix; + msg[1] = ' '; + strncpy(msg + 2, output.c_str(), sizeof(msg) - 2); + + if (g_hooking->get_original()(*g_pointers->m_send_chat_ptr, g_player_service->get_self()->get_net_data(), msg, false)) + notify::draw_chat(msg, g_player_service->get_self()->get_name(), false); + }); + } + + void chat_command_context::report_error(const std::string& error) const + { + report_output(error); + } +} \ No newline at end of file diff --git a/src/backend/context/chat_command_context.hpp b/src/backend/context/chat_command_context.hpp new file mode 100644 index 00000000..6ec9ad31 --- /dev/null +++ b/src/backend/context/chat_command_context.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "command_context.hpp" + +namespace big +{ + class chat_command_context : public command_context + { + player_ptr m_player; + public: + virtual player_ptr get_sender() const override; + virtual CommandAccessLevel get_access_level() const override; + virtual void report_output(const std::string& output) const override; + virtual void report_error(const std::string& error) const override; + + chat_command_context(player_ptr player); + }; +} \ No newline at end of file diff --git a/src/backend/context/command_context.hpp b/src/backend/context/command_context.hpp new file mode 100644 index 00000000..e3a35f27 --- /dev/null +++ b/src/backend/context/command_context.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "services/players/player_service.hpp" +#include "core/enums.hpp" + +namespace big +{ + class command_context + { + public: + virtual player_ptr get_sender() const = 0; + virtual CommandAccessLevel get_access_level() const = 0; + virtual void report_output(const std::string& output) const = 0; + virtual void report_error(const std::string& error) const = 0; + }; +} \ No newline at end of file diff --git a/src/backend/context/default_command_context.cpp b/src/backend/context/default_command_context.cpp new file mode 100644 index 00000000..a34e5072 --- /dev/null +++ b/src/backend/context/default_command_context.cpp @@ -0,0 +1,24 @@ +#include "default_command_context.hpp" + +namespace big +{ + player_ptr default_command_context::get_sender() const + { + return g_player_service->get_self(); + } + + CommandAccessLevel default_command_context::get_access_level() const + { + return CommandAccessLevel::ADMIN; + } + + void default_command_context::report_output(const std::string& output) const + { + g_notification_service->push("Command", output); + } + + void default_command_context::report_error(const std::string& error) const + { + g_notification_service->push_error("Command", error); + } +} \ No newline at end of file diff --git a/src/backend/context/default_command_context.hpp b/src/backend/context/default_command_context.hpp new file mode 100644 index 00000000..33035381 --- /dev/null +++ b/src/backend/context/default_command_context.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "command_context.hpp" + +namespace big +{ + class default_command_context : public command_context + { + public: + virtual player_ptr get_sender() const override; + virtual CommandAccessLevel get_access_level() const override; + virtual void report_output(const std::string& output) const override; + virtual void report_error(const std::string& error) const override; + default_command_context() {}; + }; +} \ No newline at end of file diff --git a/src/backend/int_command.cpp b/src/backend/int_command.cpp new file mode 100644 index 00000000..6bf4c8e3 --- /dev/null +++ b/src/backend/int_command.cpp @@ -0,0 +1,32 @@ +#include "int_command.hpp" + +namespace big +{ + int_command::int_command(const std::string& name, const std::string& label, const std::string& description, int& value, int lower_bound, int upper_bound) : + command(name, label, description, 1), + m_value(value), + m_lower_bound(lower_bound), + m_upper_bound(upper_bound) + { + } + + void int_command::execute(const std::vector& args, const std::shared_ptr ctx) + { + m_value = args[0]; + } + + std::optional> int_command::parse_args(const std::vector& args, const std::shared_ptr ctx) + { + std::vector result; + int value = std::atoi(args[0].c_str()); + + if (value < m_lower_bound || value > m_upper_bound) + { + ctx->report_error(std::format("Value {} is not between {} and {} in command {}", value, m_lower_bound, m_upper_bound, m_name)); + return std::nullopt; + } + + result.push_back(value); + return result; + } +} \ No newline at end of file diff --git a/src/backend/int_command.hpp b/src/backend/int_command.hpp new file mode 100644 index 00000000..d6211dcf --- /dev/null +++ b/src/backend/int_command.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "command.hpp" + +namespace big +{ + class int_command : command + { + protected: + int& m_value; + int m_lower_bound; + int m_upper_bound; + + virtual void execute(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + public: + int_command(const std::string& name, const std::string& label, const std::string& description, int& value, int lower_bound, int upper_bound); + inline int& get_value() { return m_value; } + }; +} \ No newline at end of file diff --git a/src/backend/looped/hud/hud_transition_state.cpp b/src/backend/looped/hud/hud_transition_state.cpp index 461a6b05..2a1105a4 100644 --- a/src/backend/looped/hud/hud_transition_state.cpp +++ b/src/backend/looped/hud/hud_transition_state.cpp @@ -2,8 +2,8 @@ #include "natives.hpp" #include "script_global.hpp" #include "gta/joaat.hpp" -#include "util/kick.hpp" #include "services/players/player_service.hpp" +#include "core/scr_globals.hpp" // Credits: QuickNET namespace big diff --git a/src/backend/looped/looped.hpp b/src/backend/looped/looped.hpp index b04b523d..c8680bc9 100644 --- a/src/backend/looped/looped.hpp +++ b/src/backend/looped/looped.hpp @@ -10,30 +10,14 @@ namespace big public: static void hud_transition_state(); - static void tunables_disable_phone(); - static void player_good_options(); static void player_spectate(); static void player_remote_control_vehicle(); - static void self_clean_player(); - static void self_free_cam_disable_control_action(); - static void self_free_cam(); static void self_godmode(); - static void self_invisibility(); - static void self_noclip_disable_control_action(); - static void self_noclip(); - static void self_no_ragdoll(); - static void self_off_radar(); static void self_police(); - static void self_super_run(); - static void self_no_collision(); static void self_hud(); - static void self_unlimited_oxygen(); - static void self_no_water_collision(); - static void self_mobile_radio(); static void self_dance_mode(); - static void self_fast_respawn(); static void session_local_time(); static void session_pop_multiplier_areas(); @@ -50,35 +34,21 @@ namespace big static void vehicle_auto_drive(); static void vehicle_boost_behavior(); - static void vehicle_drive_on_water(); static void vehicle_fly(); static void vehicle_god_mode(); - static void vehicle_horn_boost(); - static void vehicle_jump(); - static void vehicle_instant_brake(); - static void vehicle_is_targetable(); static void vehicle_ls_customs(); static void vehicle_rainbow_paint(); - static void vehicle_seatbelt(); static void vehicle_speedo_meter(); static void vehicle_turn_signals(); - static void vehicle_keep_vehicle_repaired(); - static void vehicle_no_water_collision(); static void weapons_ammo_special_type(); static void weapons_cage_gun(); static void custom_gun_disable_control_action(); static void weapons_delete_gun(); - static void weapons_force_crosshairs(); static void weapons_gravity_gun(); static void weapons_increased_damage(); - static void weapons_infinite_ammo(); - static void weapons_infinite_mag(); - static void weapons_no_recoil(); - static void weapons_no_spread(); static void weapons_repair_gun(); static void weapons_steal_vehicle_gun(); static void weapons_vehicle_gun(); - static void weapons_rapid_fire(); }; } diff --git a/src/backend/looped/self/clean_player.cpp b/src/backend/looped/self/clean_player.cpp index 3f015e5f..7bcf1026 100644 --- a/src/backend/looped/self/clean_player.cpp +++ b/src/backend/looped/self/clean_player.cpp @@ -1,13 +1,18 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" #include "util/entity.hpp" namespace big { - void looped::self_clean_player() + class clean_player_looped : looped_command { - if (g.self.clean_player) { + using looped_command::looped_command; + + virtual void on_tick() override + { entity::clean_ped(self::ped); } - } -} \ No newline at end of file + }; + + clean_player_looped g_clean_player_looped("cleanloop", "Keep Player Clean", "Prevents wetness and decals from being applied on you", g.self.clean_player); +} diff --git a/src/backend/looped/self/fast_respawn.cpp b/src/backend/looped/self/fast_respawn.cpp index f1e56841..e07bd922 100644 --- a/src/backend/looped/self/fast_respawn.cpp +++ b/src/backend/looped/self/fast_respawn.cpp @@ -1,17 +1,26 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" +#include "gta/enums.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - void looped::self_fast_respawn() - { - if (g.self.fast_respawn) - { - if(PED::IS_PED_DEAD_OR_DYING(self::ped, true)) - { - PED::RESURRECT_PED(self::ped); - ENTITY::SET_ENTITY_COORDS_NO_OFFSET(self::ped, self::pos.x, self::pos.y, self::pos.z, 0, 0, 0); - } - } - } -} \ No newline at end of file + class fast_respawn : looped_command + { + using looped_command::looped_command; + + virtual void on_tick() override + { + if (PED::IS_PED_DEAD_OR_DYING(self::ped, true)) + { + PED::RESURRECT_PED(self::ped); + ENTITY::SET_ENTITY_COORDS_NO_OFFSET(self::ped, self::pos.x, self::pos.y, self::pos.z, 0, 0, 0); + TASK::CLEAR_PED_TASKS_IMMEDIATELY(self::ped); + MISC::FORCE_GAME_STATE_PLAYING(); + } + } + }; + + fast_respawn g_fast_respawn("fastrespawn", "Instant Respawn", "Makes you respawn instantly when you die", g.self.fast_respawn); +} diff --git a/src/backend/looped/self/free_cam.cpp b/src/backend/looped/self/free_cam.cpp index 60060bf0..067262e2 100644 --- a/src/backend/looped/self/free_cam.cpp +++ b/src/backend/looped/self/free_cam.cpp @@ -1,20 +1,12 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" #include "gta/enums.hpp" #include "natives.hpp" -#include "util/globals.hpp" +#include "backend/looped_command.hpp" #include "util/math.hpp" namespace big { - static bool bLastFreeCam = false; - - static float speed = 0.5f; - static float mult = 0.f; - - static Cam cCam = -1; - static Vector3 vecPosition; - static Vector3 vecRot; - static const ControllerInputs controls[] = { ControllerInputs::INPUT_LOOK_LR, @@ -29,96 +21,91 @@ namespace big ControllerInputs::INPUT_LOOK_DOWN }; - void looped::self_free_cam_disable_control_action() + class free_cam : looped_command { - if (g_local_player == nullptr) return; + using looped_command::looped_command; - if (g.self.free_cam) + float speed = 0.5f; + float mult = 0.f; + + Cam camera = -1; + Vector3 position; + Vector3 rotation; + + virtual void on_enable() override + { + camera = CAM::CREATE_CAM("DEFAULT_SCRIPTED_CAMERA", 0); + + position = CAM::GET_GAMEPLAY_CAM_COORD(); + rotation = CAM::GET_GAMEPLAY_CAM_ROT(2); + + ENTITY::FREEZE_ENTITY_POSITION(self::veh, true); + + CAM::SET_CAM_COORD(camera, position.x, position.y, position.z); + CAM::SET_CAM_ROT(camera, rotation.x, rotation.y, rotation.z, 2); + CAM::SET_CAM_ACTIVE(camera, true); + CAM::RENDER_SCRIPT_CAMS(true, true, 500, true, true, 0); + } + + virtual void on_tick() override { PAD::DISABLE_ALL_CONTROL_ACTIONS(0); for (const auto& control : controls) PAD::ENABLE_CONTROL_ACTION(0, static_cast(control), true); + + Vector3 vecChange = { 0.f, 0.f, 0.f }; + + // Left Shift + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) + vecChange.z += speed / 2; + // Left Control + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_DUCK)) + vecChange.z -= speed / 2; + // Forward + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_UP_ONLY)) + vecChange.y += speed; + // Backward + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_DOWN_ONLY)) + vecChange.y -= speed; + // Left + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_LEFT_ONLY)) + vecChange.x -= speed; + // Right + if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_RIGHT_ONLY)) + vecChange.x += speed; + + if (vecChange.x == 0.f && vecChange.y == 0.f && vecChange.z == 0.f) + mult = 0.f; + else if (mult < 10) + mult += 0.15f; + + Vector3 rot = CAM::GET_CAM_ROT(camera, 2); + //float pitch = math::deg_to_rad(rot.x); // vertical + //float roll = rot.y; + float yaw = math::deg_to_rad(rot.z); // horizontal + + position.x += (vecChange.x * cos(yaw) - vecChange.y * sin(yaw)) * mult; + position.y += (vecChange.x * sin(yaw) + vecChange.y * cos(yaw)) * mult; + position.z += vecChange.z * mult; + + CAM::SET_CAM_COORD(camera, position.x, position.y, position.z); + STREAMING::SET_FOCUS_POS_AND_VEL(position.x, position.y, position.z, 0.f, 0.f, 0.f); + + rotation = CAM::GET_GAMEPLAY_CAM_ROT(2); + CAM::SET_CAM_ROT(camera, rotation.x, rotation.y, rotation.z, 2); } - } - void looped::self_free_cam() - { - if (g_local_player == nullptr) return; - - const auto vehicle = self::veh; - const auto ped = self::ped; - if (!g.self.free_cam && !bLastFreeCam) return; - - if (g.self.free_cam && !bLastFreeCam) + virtual void on_disable() override { - cCam = CAM::CREATE_CAM("DEFAULT_SCRIPTED_CAMERA", 0); - - vecPosition = CAM::GET_GAMEPLAY_CAM_COORD(); - vecRot = CAM::GET_GAMEPLAY_CAM_ROT(2); - - ENTITY::FREEZE_ENTITY_POSITION(vehicle, true); - - CAM::SET_CAM_COORD(cCam, vecPosition.x, vecPosition.y, vecPosition.z); - CAM::SET_CAM_ROT(cCam, vecRot.x, vecRot.y, vecRot.z, 2); - CAM::SET_CAM_ACTIVE(cCam, true); - CAM::RENDER_SCRIPT_CAMS(true, true, 500, true, true, 0); - - bLastFreeCam = true; - } - else if (!g.self.free_cam && bLastFreeCam) - { - CAM::SET_CAM_ACTIVE(cCam, false); + CAM::SET_CAM_ACTIVE(camera, false); CAM::RENDER_SCRIPT_CAMS(false, true, 500, true, true, 0); - CAM::DESTROY_CAM(cCam, false); - STREAMING::SET_FOCUS_ENTITY(ped); + CAM::DESTROY_CAM(camera, false); + STREAMING::CLEAR_FOCUS(); - ENTITY::FREEZE_ENTITY_POSITION(vehicle, false); - - bLastFreeCam = false; - - return; + ENTITY::FREEZE_ENTITY_POSITION(camera, false); } + }; - Vector3 vecChange = { 0.f, 0.f, 0.f }; - - // Left Shift - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) - vecChange.z += speed / 2; - // Left Control - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_DUCK)) - vecChange.z -= speed / 2; - // Forward - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_UP_ONLY)) - vecChange.y += speed; - // Backward - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_DOWN_ONLY)) - vecChange.y -= speed; - // Left - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_LEFT_ONLY)) - vecChange.x -= speed; - // Right - if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_RIGHT_ONLY)) - vecChange.x += speed; - - if (vecChange.x == 0.f && vecChange.y == 0.f && vecChange.z == 0.f) - mult = 0.f; - else if (mult < 10) - mult += 0.15f; - - Vector3 rot = CAM::GET_CAM_ROT(cCam, 2); - //float pitch = math::deg_to_rad(rot.x); // vertical - //float roll = rot.y; - float yaw = math::deg_to_rad(rot.z); // horizontal - - vecPosition.x += (vecChange.x * cos(yaw) - vecChange.y * sin(yaw)) * mult; - vecPosition.y += (vecChange.x * sin(yaw) + vecChange.y * cos(yaw)) * mult; - vecPosition.z += vecChange.z * mult; - - CAM::SET_CAM_COORD(cCam, vecPosition.x, vecPosition.y, vecPosition.z); - STREAMING::SET_FOCUS_POS_AND_VEL(vecPosition.x, vecPosition.y, vecPosition.z, 0.f, 0.f, 0.f); - - vecRot = CAM::GET_GAMEPLAY_CAM_ROT(2); - CAM::SET_CAM_ROT(cCam, vecRot.x, vecRot.y, vecRot.z, 2); - } -} + free_cam g_free_cam("freecam", "Freecam", "Allows you to move your camera freely?", g.self.free_cam); +} \ No newline at end of file diff --git a/src/backend/looped/self/invisibility.cpp b/src/backend/looped/self/invisibility.cpp index ee196e40..fa47de70 100644 --- a/src/backend/looped/self/invisibility.cpp +++ b/src/backend/looped/self/invisibility.cpp @@ -1,36 +1,27 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastInvisibility = false; - - void looped::self_invisibility() + class invisibility : looped_command { - Ped ped = self::ped; + using looped_command::looped_command; - bool bInvisibility = g.self.invisibility; - - if (bInvisibility || (!bInvisibility && bInvisibility != bLastInvisibility)) - { - ENTITY::SET_ENTITY_VISIBLE(ped, !g.self.invisibility, 0); - - bLastInvisibility = g.self.invisibility; - } - - if (NETWORK::NETWORK_IS_SESSION_STARTED()) - { - if (g.self.invisibility && g.self.local_visibility) - { - NETWORK::SET_ENTITY_LOCALLY_VISIBLE(ped); - } - } - else + virtual void on_tick() override { + ENTITY::SET_ENTITY_VISIBLE(self::ped, false, 0); if (g.self.local_visibility) - { - ENTITY::SET_ENTITY_VISIBLE(ped, true, 0); - } + NETWORK::SET_ENTITY_LOCALLY_VISIBLE(self::ped); } - } + + virtual void on_disable() override + { + ENTITY::SET_ENTITY_VISIBLE(self::ped, true, 0); + } + }; + + invisibility g_invisibility("invis", "Invisiblity", "Makes you invisible", g.self.invisibility); + bool_command g_local_visibility("localvis", "Visible Locally", "Makes you visible to yourself, other players will still not be able to see you", g.self.local_visibility); } diff --git a/src/backend/looped/self/mobile_radio.cpp b/src/backend/looped/self/mobile_radio.cpp index d14a1216..4159fbd3 100644 --- a/src/backend/looped/self/mobile_radio.cpp +++ b/src/backend/looped/self/mobile_radio.cpp @@ -1,25 +1,24 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastMobileRadio = false; - - void looped::self_mobile_radio() + class mobile_radio : looped_command { - const bool bMobileRadio = g.self.mobile_radio; + using looped_command::looped_command; - if (bMobileRadio) + virtual void on_tick() override { AUDIO::SET_MOBILE_PHONE_RADIO_STATE(true); AUDIO::SET_MOBILE_RADIO_ENABLED_DURING_GAMEPLAY(true); } - else if (bMobileRadio != bLastMobileRadio) + + virtual void on_disable() override { AUDIO::SET_MOBILE_PHONE_RADIO_STATE(false); AUDIO::SET_MOBILE_RADIO_ENABLED_DURING_GAMEPLAY(false); } + }; - bLastMobileRadio = bMobileRadio; - } + mobile_radio g_mobile_radio("mobileradio", "Mobile Radio", "Allows you to listen to the radio on foot", g.self.mobile_radio); } diff --git a/src/backend/looped/self/no_collision.cpp b/src/backend/looped/self/no_collision.cpp index 14a92152..bdd80e82 100644 --- a/src/backend/looped/self/no_collision.cpp +++ b/src/backend/looped/self/no_collision.cpp @@ -1,26 +1,28 @@ #include "backend/looped/looped.hpp" -#include "base/phArchetype.hpp" -#include "base/phBoundComposite.hpp" +#include "fiber_pool.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" +#include +#include namespace big { - static bool bLastNoCollsion = false; - - void looped::self_no_collision() + class no_collision : looped_command { - if (g_local_player == nullptr) return; + using looped_command::looped_command; - bool bNoCollsion = g.self.no_collision; + virtual void on_tick() override + { + if (g_local_player) + ((rage::phBoundComposite*)g_local_player->m_navigation->m_damp->m_bound)->m_bounds[0]->m_bounding_box_max_xyz_margin_w.w = -1; + } - if (bNoCollsion) + virtual void on_disable() override { - ((rage::phBoundComposite*)g_local_player->m_navigation->m_damp->m_bound)->m_bounds[0]->m_bounding_box_max_xyz_margin_w.w = -1; - bLastNoCollsion = bNoCollsion; + if (g_local_player) + ((rage::phBoundComposite*)g_local_player->m_navigation->m_damp->m_bound)->m_bounds[0]->m_bounding_box_max_xyz_margin_w.w = 0.25; } - else if (bNoCollsion != bLastNoCollsion) - { - ((rage::phBoundComposite*)g_local_player->m_navigation->m_damp->m_bound)->m_bounds[0]->m_bounding_box_max_xyz_margin_w.w = 0.25; - bLastNoCollsion = bNoCollsion; - } - } + }; + + no_collision g_no_collision("nocollision", "No Collision", "Allows you to walk through vehicles and most obstacles", g.self.no_collision); } diff --git a/src/backend/looped/self/no_ragdoll.cpp b/src/backend/looped/self/no_ragdoll.cpp index 1e33dc6b..81eed534 100644 --- a/src/backend/looped/self/no_ragdoll.cpp +++ b/src/backend/looped/self/no_ragdoll.cpp @@ -1,19 +1,24 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastNoRagdoll = false; - - void looped::self_no_ragdoll() + class no_ragdoll : looped_command { - bool bNoRagdoll = g.self.no_ragdoll; + using looped_command::looped_command; - if (bNoRagdoll || (!bNoRagdoll && bNoRagdoll != bLastNoRagdoll)) + virtual void on_tick() override { - PED::SET_PED_CAN_RAGDOLL(self::ped, !g.self.no_ragdoll); - - bLastNoRagdoll = g.self.no_ragdoll; + PED::SET_PED_CAN_RAGDOLL(self::ped, false); } - } + + virtual void on_disable() override + { + PED::SET_PED_CAN_RAGDOLL(self::ped, true); + } + }; + + no_ragdoll g_no_ragdoll("noragdoll", "No Ragdoll", "Prevents you from ragdolling", g.self.no_ragdoll); } diff --git a/src/backend/looped/self/no_water_collision.cpp b/src/backend/looped/self/no_water_collision.cpp index ab4bd9ab..d6bd3514 100644 --- a/src/backend/looped/self/no_water_collision.cpp +++ b/src/backend/looped/self/no_water_collision.cpp @@ -1,24 +1,26 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastSelfNoWaterCollsion = false; - - void looped::self_no_water_collision() + class no_water_collision : looped_command { - if (g_local_player == nullptr) return; + using looped_command::looped_command; - bool bNoWaterCollsion = g.self.no_water_collision; + virtual void on_tick() override + { + if (g_local_player) + g_local_player->m_navigation->m_damp->m_water_collision = 0; + } - if (bNoWaterCollsion) + virtual void on_disable() override { - g_local_player->m_navigation->m_damp->m_water_collision = 0; - bLastSelfNoWaterCollsion = bNoWaterCollsion; + if (g_local_player) + g_local_player->m_navigation->m_damp->m_water_collision = 1; } - else if (bNoWaterCollsion != bLastSelfNoWaterCollsion) - { - g_local_player->m_navigation->m_damp->m_water_collision = 1; - bLastSelfNoWaterCollsion = bNoWaterCollsion; - } - } -} \ No newline at end of file + }; + + no_water_collision g_no_water_collision("walkunder", "Walk Underwater", "Allows you to walk and shoot underwater", g.self.no_water_collision); +} diff --git a/src/backend/looped/self/noclip.cpp b/src/backend/looped/self/noclip.cpp index 276e1ba7..6cf7dcbe 100644 --- a/src/backend/looped/self/noclip.cpp +++ b/src/backend/looped/self/noclip.cpp @@ -3,10 +3,11 @@ #include "gta/enums.hpp" #include "natives.hpp" #include "util/entity.hpp" +#include "backend/looped_command.hpp" namespace big { - static const ControllerInputs controls[] = + static constexpr ControllerInputs controls[] = { ControllerInputs::INPUT_SPRINT, ControllerInputs::INPUT_MOVE_UP_ONLY, @@ -16,41 +17,32 @@ namespace big ControllerInputs::INPUT_DUCK }; - static float speed = 20.f; - static float mult = 0.f; + static constexpr float speed = 20.f; - static bool bLastNoclip = false; - - static Entity prev = -1; - static Vector3 rot{}; - - void looped::self_noclip_disable_control_action() + class noclip : looped_command { - if (g.self.noclip) + using looped_command::looped_command; + + Entity m_entity; + float m_speed_multiplier; + + virtual void on_tick() override { for (const auto& control : controls) PAD::DISABLE_CONTROL_ACTION(0, static_cast(control), true); - } - } - void looped::self_noclip() - { - const auto bNoclip = g.self.noclip; + const auto location = self::pos; + const Entity ent = (self::veh != 0 && g_local_player->m_ped_task_flag & (int)ePedTask::TASK_DRIVING) ? self::veh : self::ped; - const auto location = self::pos; - const Entity ent = (self::veh != 0 && g_local_player->m_ped_task_flag & (int)ePedTask::TASK_DRIVING) ? self::veh : self::ped; + // cleanup when changing entities + if (m_entity != ent) + { + ENTITY::FREEZE_ENTITY_POSITION(m_entity, false); + ENTITY::SET_ENTITY_COLLISION(m_entity, true, true); - // cleanup when changing entities - if (prev != ent) - { - ENTITY::FREEZE_ENTITY_POSITION(prev, false); - ENTITY::SET_ENTITY_COLLISION(prev, true, true); + m_entity = ent; + } - prev = ent; - } - - if (bNoclip) - { Vector3 vel = { 0.f, 0.f, 0.f }; // Left Shift @@ -72,20 +64,19 @@ namespace big if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_MOVE_RIGHT_ONLY)) vel.x += speed; - rot = CAM::GET_GAMEPLAY_CAM_ROT(2); + auto rot = CAM::GET_GAMEPLAY_CAM_ROT(2); ENTITY::SET_ENTITY_ROTATION(ent, 0.f, rot.y, rot.z, 2, 0); ENTITY::SET_ENTITY_COLLISION(ent, false, false); if (vel.x == 0.f && vel.y == 0.f && vel.z == 0.f) { // freeze entity to prevent drifting when standing still ENTITY::FREEZE_ENTITY_POSITION(ent, true); - - mult = 0.f; + m_speed_multiplier = 0.f; } else { - if (mult < 20.f) - mult += 0.15f; + if (m_speed_multiplier < 20.f) + m_speed_multiplier += 0.15f; ENTITY::FREEZE_ENTITY_POSITION(ent, false); @@ -93,18 +84,19 @@ namespace big vel.x = offset.x - location.x; vel.y = offset.y - location.y; - ENTITY::SET_ENTITY_VELOCITY(ent, vel.x * mult, vel.y * mult, vel.z * mult); - } - } - else if (bNoclip != bLastNoclip) - { - if (entity::take_control_of(ent)) - { - ENTITY::FREEZE_ENTITY_POSITION(ent, false); - ENTITY::SET_ENTITY_COLLISION(ent, true, false); + ENTITY::SET_ENTITY_VELOCITY(ent, vel.x * m_speed_multiplier, vel.y * m_speed_multiplier, vel.z * m_speed_multiplier); } } - bLastNoclip = bNoclip; - } + virtual void on_disable() override + { + if (entity::take_control_of(m_entity)) + { + ENTITY::FREEZE_ENTITY_POSITION(m_entity, false); + ENTITY::SET_ENTITY_COLLISION(m_entity, true, false); + } + } + }; + + noclip g_noclip("noclip", "No Clip", "Allows you to fly through the map", g.self.noclip); } diff --git a/src/backend/looped/self/off_radar.cpp b/src/backend/looped/self/off_radar.cpp index dee8ece4..1e3b81c8 100644 --- a/src/backend/looped/self/off_radar.cpp +++ b/src/backend/looped/self/off_radar.cpp @@ -1,11 +1,24 @@ -#include "backend/looped/looped.hpp" -#include "util/mobile.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" +#include "core/scr_globals.hpp" namespace big { - void looped::self_off_radar() + class off_radar : looped_command { - if (g.self.off_radar) - mobile::lester::off_radar(g.self.off_radar); - } -} \ No newline at end of file + using looped_command::looped_command; + + virtual void on_tick() override + { + *scr_globals::globalplayer_bd.at(PLAYER::GET_PLAYER_INDEX(), scr_globals::size::globalplayer_bd).at(210).as() = true; + *script_global(2672505).at(56).as() = NETWORK::GET_NETWORK_TIME() + 1; + } + + virtual void on_disable() override + { + *scr_globals::globalplayer_bd.at(PLAYER::GET_PLAYER_INDEX(), scr_globals::size::globalplayer_bd).at(210).as() = false; + } + }; + + off_radar g_off_radar("otr", "Off Radar", "Hides your blip from other players", g.self.off_radar); +} diff --git a/src/backend/looped/self/super_run.cpp b/src/backend/looped/self/super_run.cpp index d74bf5ba..510e4e44 100644 --- a/src/backend/looped/self/super_run.cpp +++ b/src/backend/looped/self/super_run.cpp @@ -1,53 +1,65 @@ -#include "backend/looped/looped.hpp" #include "gta/enums.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" #include "util/math.hpp" namespace big { - static float run_speed = 10.f; - static float run_cap = 100.f; - static bool super_run_state = false; - - void looped::self_super_run() + class super_run : looped_command { - if (g.self.super_run && PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) + using looped_command::looped_command; + + const float run_cap = 100.f; + float run_speed = 10.f; + + virtual void on_tick() override { - if (run_speed < run_cap) run_speed += .5f; + if (g_local_player) + { + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_SPRINT)) + { + if (run_speed < run_cap) + run_speed += .5f; - Vector3 location = self::pos; - Ped ped = self::ped; + Vector3 location = self::pos; + Ped ped = self::ped; - //Vector3 rot = CAM::GET_GAMEPLAY_CAM_ROT(2); - Vector3 rot = ENTITY::GET_ENTITY_ROTATION(ped, 2); - float yaw = math::deg_to_rad(rot.z + 90); + Vector3 rot = ENTITY::GET_ENTITY_ROTATION(ped, 2); + float yaw = math::deg_to_rad(rot.z + 90); - Vector3 offset; - offset.x = location.x + (run_speed * cos(yaw)); - offset.y = location.y + (run_speed * sin(yaw)); - offset.z = location.z + .2f; + Vector3 offset; + offset.x = location.x + (run_speed * cos(yaw)); + offset.y = location.y + (run_speed * sin(yaw)); + offset.z = location.z + .2f; - float groundZ; - MISC::GET_GROUND_Z_FOR_3D_COORD(offset.x, offset.y, 1000.f, &groundZ, false, false); - if (groundZ < location.z) - offset.z = groundZ; + float groundZ; + MISC::GET_GROUND_Z_FOR_3D_COORD(offset.x, offset.y, 1000.f, &groundZ, false, false); + if (groundZ < location.z) + offset.z = groundZ; - Vector3 vel = offset - location; + Vector3 vel = offset - location; - ENTITY::SET_ENTITY_VELOCITY(ped, vel.x, vel.y, vel.z); + ENTITY::SET_ENTITY_VELOCITY(ped, vel.x, vel.y, vel.z); - g_local_player->m_player_info->m_run_speed = .7f; - } - else if (!g.self.super_run && g.self.super_run != super_run_state) - { - g_local_player->m_player_info->m_run_speed = 1.f; - } - else if (PAD::IS_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_SPRINT)) - { - run_speed = 10.f; - g_local_player->m_player_info->m_run_speed = 1.f; + g_local_player->m_player_info->m_run_speed = .7f; + } + else if (PAD::IS_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_SPRINT)) + { + run_speed = 10.f; + g_local_player->m_player_info->m_run_speed = 1.f; + } + } } - super_run_state = g.self.super_run; - } -} \ No newline at end of file + virtual void on_disable() override + { + if (g_local_player) + { + run_speed = 10.f; + g_local_player->m_player_info->m_run_speed = 1.f; + } + } + }; + + super_run g_super_run("fastrun", "Super Run", "Makes you run much faster", g.self.super_run); +} diff --git a/src/backend/looped/self/unlimited_oxygen.cpp b/src/backend/looped/self/unlimited_oxygen.cpp index 4506e220..3d6d9495 100644 --- a/src/backend/looped/self/unlimited_oxygen.cpp +++ b/src/backend/looped/self/unlimited_oxygen.cpp @@ -1,12 +1,18 @@ -#include "backend/looped/looped.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - void looped::self_unlimited_oxygen() + class unlimited_oxygen : looped_command { - if (g_local_player == nullptr) return; + using looped_command::looped_command; - if (g.self.unlimited_oxygen) - g_local_player->m_oxygen_info->m_oxygen_time = 0; - } -} \ No newline at end of file + virtual void on_tick() override + { + if (g_local_player) + g_local_player->m_oxygen_info->m_oxygen_time = 0; + } + }; + + unlimited_oxygen g_unlimited_oxygen("infoxy", "Unlimited Oxygen", "Allows you to stay underwater without losing oxygen", g.self.unlimited_oxygen); +} diff --git a/src/backend/looped/session/auto_kick_host.cpp b/src/backend/looped/session/auto_kick_host.cpp index 125a614a..2d5eddb2 100644 --- a/src/backend/looped/session/auto_kick_host.cpp +++ b/src/backend/looped/session/auto_kick_host.cpp @@ -1,7 +1,7 @@ #include "backend/looped/looped.hpp" #include "natives.hpp" #include "pointers.hpp" -#include "util/kick.hpp" +#include "backend/player_command.hpp" namespace big { @@ -14,7 +14,9 @@ namespace big g_player_service->iterate([](auto& plyr) { if (plyr.second->is_host()) - kick::lost_connection_kick(plyr.second); + { + ((player_command*)(command::get(RAGE_JOAAT("lckick"))))->call(plyr.second, {}); + } }); } bLastKickHost = kick_host; diff --git a/src/backend/looped/system/desync_kick_protection.cpp b/src/backend/looped/system/desync_kick_protection.cpp index 09be8894..706e993a 100644 --- a/src/backend/looped/system/desync_kick_protection.cpp +++ b/src/backend/looped/system/desync_kick_protection.cpp @@ -10,6 +10,9 @@ namespace big { void looped::system_desync_kick_protection() { + if (g_player_service->get_self()->is_valid() && g_player_service->get_self()->is_host()) + return; + memset(>a_util::get_network()->m_game_complaint_mgr.m_host_tokens_complained, 0, 64 * sizeof(std::uint64_t)); if (!g_player_service->m_player_to_use_complaint_kick || !g_player_service->m_player_to_use_complaint_kick->get()->get_net_data()) gta_util::get_network()->m_game_complaint_mgr.m_num_tokens_complained = 0; diff --git a/src/backend/looped/tunables/disable_phone.cpp b/src/backend/looped/tunables/disable_phone.cpp index 2b5ea1f0..6879f082 100644 --- a/src/backend/looped/tunables/disable_phone.cpp +++ b/src/backend/looped/tunables/disable_phone.cpp @@ -1,10 +1,23 @@ -#include "backend/looped/looped.hpp" -#include "script_global.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" +#include "core/scr_globals.hpp" namespace big { - void looped::tunables_disable_phone() + class disable_phone : looped_command { - *script_global(20366).as() = g.tunables.disable_phone; // Who even uses that... - } -} \ No newline at end of file + using looped_command::looped_command; + + virtual void on_tick() override + { + *script_global(20366).as() = true; + } + + virtual void on_disable() override + { + *script_global(20366).as() = false; + } + }; + + disable_phone g_disable_phone("nophone", "Disable Phone", "Blocks phone and stops all phone calls", g.tunables.disable_phone); +} diff --git a/src/backend/looped/vehicle/block_homing.cpp b/src/backend/looped/vehicle/block_homing.cpp new file mode 100644 index 00000000..0284f6f3 --- /dev/null +++ b/src/backend/looped/vehicle/block_homing.cpp @@ -0,0 +1,25 @@ +#include "natives.hpp" +#include "backend/looped_command.hpp" +#include "gta/enums.hpp" + +namespace big +{ + class block_homing : looped_command + { + using looped_command::looped_command; + + virtual void on_tick() override + { + if (g_local_player && g_local_player->m_vehicle) + g_local_player->m_vehicle->m_is_targetable = false; + } + + virtual void on_disable() override + { + if (g_local_player && g_local_player->m_vehicle) + g_local_player->m_vehicle->m_is_targetable = true; + } + }; + + block_homing g_block_homing("blockhoming", "Block Homing Missiles", "Prevents homing missiles from locking on to your vehicle", g.vehicle.block_homing); +} diff --git a/src/backend/looped/vehicle/drive_on_water.cpp b/src/backend/looped/vehicle/drive_on_water.cpp index cb7b68de..635f7737 100644 --- a/src/backend/looped/vehicle/drive_on_water.cpp +++ b/src/backend/looped/vehicle/drive_on_water.cpp @@ -1,93 +1,99 @@ #include "backend/looped/looped.hpp" +#include "fiber_pool.hpp" #include "natives.hpp" -#include "script.hpp" +#include "backend/looped_command.hpp" #include "util/entity.hpp" namespace big { - constexpr auto drive_on_water_surface_hash = RAGE_JOAAT("stt_prop_stunt_bblock_xl3"); - static Vector3 drive_on_water_last_loc; - - void drive_on_water_hide_surface() + class drive_on_water : looped_command { - Object surface = OBJECT::GET_CLOSEST_OBJECT_OF_TYPE( - drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, - 4.0, drive_on_water_surface_hash, 0, 0, 1 - ); + using looped_command::looped_command; - if (surface) - { - entity::take_control_of(surface); - ENTITY::SET_ENTITY_COORDS(surface, 0, 0, -1000.0f, 0, 0, 0, 1); - script::get_current()->yield(10ms); - ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&surface); - ENTITY::DELETE_ENTITY(&surface); - WATER::RESET_DEEP_OCEAN_SCALER(); - } - } + const rage::joaat_t drive_on_water_surface_hash = RAGE_JOAAT("stt_prop_stunt_bblock_xl3"); + Vector3 drive_on_water_last_loc; - - void looped::vehicle_drive_on_water() - { - if (!g.vehicle.drive_on_water || self::veh == 0) { - drive_on_water_hide_surface(); - return; - } - - Vector3 location = ENTITY::GET_ENTITY_COORDS(self::veh, 1); - float height = 0; - - WATER::SET_DEEP_OCEAN_SCALER(0); - if (location.z - height < 10 && WATER::GET_WATER_HEIGHT_NO_WAVES(location.x, location.y, location.z, &height)) + void drive_on_water_hide_surface() { Object surface = OBJECT::GET_CLOSEST_OBJECT_OF_TYPE( drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, 4.0, drive_on_water_surface_hash, 0, 0, 1 ); - if (ENTITY::DOES_ENTITY_EXIST(surface) && height > -50.0f) + if (surface) { entity::take_control_of(surface); + ENTITY::SET_ENTITY_COORDS(surface, 0, 0, -1000.0f, 0, 0, 0, 1); + ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&surface); + ENTITY::DELETE_ENTITY(&surface); + WATER::RESET_DEEP_OCEAN_SCALER(); + } + } - drive_on_water_last_loc = location; - drive_on_water_last_loc.z = height - 0.5f; - ENTITY::SET_ENTITY_COORDS( - surface, - drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, - 0, 0, 0, 0 + virtual void on_tick() override + { + Vector3 location = ENTITY::GET_ENTITY_COORDS(self::veh, 1); + float height = 0; + + WATER::SET_DEEP_OCEAN_SCALER(0); + if (location.z - height < 10 && WATER::GET_WATER_HEIGHT_NO_WAVES(location.x, location.y, location.z, &height) && self::veh) + { + Object surface = OBJECT::GET_CLOSEST_OBJECT_OF_TYPE( + drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, + 4.0, drive_on_water_surface_hash, 0, 0, 1 ); - if (location.z < height - 2.f) + if (ENTITY::DOES_ENTITY_EXIST(surface) && height > -50.0f) { - entity::take_control_of(self::veh); - ENTITY::SET_ENTITY_COORDS(self::veh, location.x, location.y, height, 0, 0, 0, 0); + entity::take_control_of(surface); + + drive_on_water_last_loc = location; + drive_on_water_last_loc.z = height - 0.5f; + ENTITY::SET_ENTITY_COORDS( + surface, + drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, + 0, 0, 0, 0 + ); + + if (location.z < height - 2.f) + { + entity::take_control_of(self::veh); + ENTITY::SET_ENTITY_COORDS(self::veh, location.x, location.y, height, 0, 0, 0, 0); + } + } + else + { + STREAMING::REQUEST_MODEL(drive_on_water_surface_hash); + while (!STREAMING::HAS_MODEL_LOADED(drive_on_water_surface_hash)) + { + script::get_current()->yield(); + } + + drive_on_water_last_loc = location; + drive_on_water_last_loc.z = height - 0.5f; + surface = OBJECT::CREATE_OBJECT( + drive_on_water_surface_hash, + drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, + 1, 1, 0 + ); + + entity::take_control_of(surface); + ENTITY::FREEZE_ENTITY_POSITION(surface, 1); + ENTITY::SET_ENTITY_ALPHA(surface, 0, 1); + ENTITY::SET_ENTITY_VISIBLE(surface, false, 0); } } else { - STREAMING::REQUEST_MODEL(drive_on_water_surface_hash); - while (!STREAMING::HAS_MODEL_LOADED(drive_on_water_surface_hash)) - { - script::get_current()->yield(); - } - - drive_on_water_last_loc = location; - drive_on_water_last_loc.z = height - 0.5f; - surface = OBJECT::CREATE_OBJECT( - drive_on_water_surface_hash, - drive_on_water_last_loc.x, drive_on_water_last_loc.y, drive_on_water_last_loc.z, - 1, 1, 0 - ); - - entity::take_control_of(surface); - ENTITY::FREEZE_ENTITY_POSITION(surface, 1); - ENTITY::SET_ENTITY_ALPHA(surface, 0, 1); - ENTITY::SET_ENTITY_VISIBLE(surface, false, 0); + drive_on_water_hide_surface(); } } - else + + virtual void on_disable() override { drive_on_water_hide_surface(); } - } + }; + + drive_on_water g_drive_on_water("driveonwater", "Drive On Water", "Allows you to drive on water", g.vehicle.drive_on_water); } diff --git a/src/backend/looped/vehicle/horn_boost.cpp b/src/backend/looped/vehicle/horn_boost.cpp index 462e2a8c..92032dfc 100644 --- a/src/backend/looped/vehicle/horn_boost.cpp +++ b/src/backend/looped/vehicle/horn_boost.cpp @@ -1,38 +1,44 @@ -#include "backend/looped/looped.hpp" -#include "gta/enums.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" +#include "gta/enums.hpp" namespace big { - static constexpr float hornBoostSpeedDefault = 10.f; - static float hornBoostSpeed = hornBoostSpeedDefault; - static constexpr float hostBoostSpeedMax = 200.f; - - void looped::vehicle_horn_boost() + class horn_boost : looped_command { - if (!g.vehicle.horn_boost) return; - - Vehicle vehicle = self::veh; + using looped_command::looped_command; + static constexpr float horn_boost_speed_default = 10.f; + static constexpr float horn_boost_speed_max = 200.f; + static constexpr float horn_boost_speed_increment = 0.3f; - if (vehicle == 0) + float horn_boost_speed = horn_boost_speed_default; + + virtual void on_tick() override { - hornBoostSpeed = hornBoostSpeedDefault; + Vehicle vehicle = self::veh; - return; + if (vehicle == 0) + { + horn_boost_speed = horn_boost_speed_default; + return; + } + + if (PAD::IS_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HORN)) + horn_boost_speed = ENTITY::GET_ENTITY_SPEED(vehicle); + + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HORN)) + { + if (horn_boost_speed < horn_boost_speed_max) + horn_boost_speed += horn_boost_speed_increment; + + const auto velocity = + ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehicle, 0.f, horn_boost_speed, 0.f) - ENTITY::GET_ENTITY_COORDS(vehicle, true); + ENTITY::SET_ENTITY_VELOCITY(vehicle, velocity.x, velocity.y, velocity.z); + } + else if (PAD::IS_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_VEH_HORN)) + horn_boost_speed = horn_boost_speed_default; } + }; - if (PAD::IS_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HORN)) - hornBoostSpeed = ENTITY::GET_ENTITY_SPEED(vehicle); - - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HORN)) - { - if (hornBoostSpeed < hostBoostSpeedMax) hornBoostSpeed++; - - const auto velocity = - ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehicle, 0.f, hornBoostSpeed, 0.f) - ENTITY::GET_ENTITY_COORDS(vehicle, true); - ENTITY::SET_ENTITY_VELOCITY(vehicle, velocity.x, velocity.y, velocity.z); - } - else if (PAD::IS_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_VEH_HORN)) - hornBoostSpeed = hornBoostSpeedDefault; - } -} \ No newline at end of file + horn_boost g_horn_boost("hornboost", "Horn Boost", "Boosts your vehicle forward when you sound the horn", g.vehicle.horn_boost); +} diff --git a/src/backend/looped/vehicle/instant_brake.cpp b/src/backend/looped/vehicle/instant_brake.cpp index 231ddd7f..1267434d 100644 --- a/src/backend/looped/vehicle/instant_brake.cpp +++ b/src/backend/looped/vehicle/instant_brake.cpp @@ -1,22 +1,22 @@ -#include "backend/looped/looped.hpp" -#include "gta/enums.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" +#include "gta/enums.hpp" namespace big { - - void looped::vehicle_instant_brake() + class instant_brake : looped_command { - if (!g.vehicle.instant_brake) return; + using looped_command::looped_command; - Vehicle vehicle = self::veh; - - if (vehicle == 0 || ENTITY::GET_ENTITY_SPEED_VECTOR(vehicle, true).y < 1.f || !VEHICLE::IS_VEHICLE_ON_ALL_WHEELS(vehicle)) + virtual void on_tick() override { - return; - } + if (self::veh == 0 || ENTITY::GET_ENTITY_SPEED_VECTOR(self::veh, true).y < 1.f || !VEHICLE::IS_VEHICLE_ON_ALL_WHEELS(self::veh)) + return; - if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_BRAKE) || PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HANDBRAKE)) - VEHICLE::SET_VEHICLE_FORWARD_SPEED(vehicle, 0); - } + if (PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_BRAKE) || PAD::IS_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HANDBRAKE)) + VEHICLE::SET_VEHICLE_FORWARD_SPEED(self::veh, 0); + } + }; + + instant_brake g_instant_brake("instantbrake", "Instant Brake", "Makes your vehicle stop instantly when you press the brake", g.vehicle.instant_brake); } diff --git a/src/backend/looped/vehicle/is_targetable.cpp b/src/backend/looped/vehicle/is_targetable.cpp deleted file mode 100644 index 5f830196..00000000 --- a/src/backend/looped/vehicle/is_targetable.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "backend/looped/looped.hpp" - -namespace big -{ - void looped::vehicle_is_targetable() - { - if (g_local_player && g_local_player->m_vehicle) - g_local_player->m_vehicle->m_is_targetable = g.vehicle.is_targetable; - } -} \ No newline at end of file diff --git a/src/backend/looped/vehicle/keep_vehicle_repaired.cpp b/src/backend/looped/vehicle/keep_vehicle_repaired.cpp index fc43a1eb..3aebc524 100644 --- a/src/backend/looped/vehicle/keep_vehicle_repaired.cpp +++ b/src/backend/looped/vehicle/keep_vehicle_repaired.cpp @@ -1,12 +1,19 @@ -#include "backend/looped/looped.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" #include "util/vehicle.hpp" namespace big { - void looped::vehicle_keep_vehicle_repaired() + class keep_vehicle_repaired : looped_command { - if (g.vehicle.keep_vehicle_repaired && VEHICLE::GET_DOES_VEHICLE_HAVE_DAMAGE_DECALS(self::veh)) { - vehicle::repair(self::veh); + using looped_command::looped_command; + + virtual void on_tick() override + { + if (VEHICLE::GET_DOES_VEHICLE_HAVE_DAMAGE_DECALS(self::veh)) + vehicle::repair(self::veh); } - } -} \ No newline at end of file + }; + + keep_vehicle_repaired g_keep_vehicle_repaired("keepfixed", "Keep Vehicle Repaired", "Keeps your vehicle free of wear and tear", g.vehicle.keep_vehicle_repaired); +} diff --git a/src/backend/looped/vehicle/no_water_collision.cpp b/src/backend/looped/vehicle/no_water_collision.cpp index 1307d9c8..280b2c14 100644 --- a/src/backend/looped/vehicle/no_water_collision.cpp +++ b/src/backend/looped/vehicle/no_water_collision.cpp @@ -1,24 +1,24 @@ -#include "backend/looped/looped.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastVehicleNoWaterCollsion = false; - - void looped::vehicle_no_water_collision() + class no_vehicle_water_collision : looped_command { - if (g_local_player == nullptr || g_local_player->m_vehicle == nullptr) return; + using looped_command::looped_command; - bool bNoWaterCollsion = g.vehicle.no_water_collision; + virtual void on_tick() override + { + if (g_local_player && g_local_player->m_vehicle) + g_local_player->m_vehicle->m_navigation->m_damp->m_water_collision = 0; + } - if (bNoWaterCollsion) + virtual void on_disable() override { - g_local_player->m_vehicle->m_navigation->m_damp->m_water_collision = 0; - bLastVehicleNoWaterCollsion = bNoWaterCollsion; + if (g_local_player && g_local_player->m_vehicle) + g_local_player->m_vehicle->m_navigation->m_damp->m_water_collision = 1; } - else if (bNoWaterCollsion != bLastVehicleNoWaterCollsion) - { - g_local_player->m_vehicle->m_navigation->m_damp->m_water_collision = 1; - bLastVehicleNoWaterCollsion = bNoWaterCollsion; - } - } -} \ No newline at end of file + }; + + no_vehicle_water_collision g_no_vehicle_water_collision("driveunder", "Drive Underwater", "Allows you to drive underwater", g.vehicle.no_water_collision); +} diff --git a/src/backend/looped/vehicle/seatbelt.cpp b/src/backend/looped/vehicle/seatbelt.cpp index 45335f70..2f2436a8 100644 --- a/src/backend/looped/vehicle/seatbelt.cpp +++ b/src/backend/looped/vehicle/seatbelt.cpp @@ -1,21 +1,24 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool b_last_seatbelt = false; - - void looped::vehicle_seatbelt() + class seatbelt : looped_command { - bool b_seatbelt = g.vehicle.seatbelt; + using looped_command::looped_command; - if (b_seatbelt || (!b_seatbelt && b_seatbelt != b_last_seatbelt)) + virtual void on_tick() override { - PED::SET_PED_CONFIG_FLAG(self::ped, 32, g.vehicle.seatbelt); - - PED::SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(self::ped, g.vehicle.seatbelt); - - b_last_seatbelt = g.vehicle.seatbelt; + PED::SET_PED_CONFIG_FLAG(self::ped, 32, true); + PED::SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(self::ped, true); } - } + + virtual void on_disable() override + { + PED::SET_PED_CONFIG_FLAG(self::ped, 32, false); + PED::SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(self::ped, false); + } + }; + + seatbelt g_seatbelt("seatbelt", "Seatbelt", "Prevent you from falling off bikes or flying through the windshield", g.vehicle.no_water_collision); } diff --git a/src/backend/looped/vehicle/vehicle_jump.cpp b/src/backend/looped/vehicle/vehicle_jump.cpp index d0756e40..5686f437 100644 --- a/src/backend/looped/vehicle/vehicle_jump.cpp +++ b/src/backend/looped/vehicle/vehicle_jump.cpp @@ -1,23 +1,21 @@ -#include "backend/looped/looped.hpp" -#include "gta/enums.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" +#include "gta/enums.hpp" namespace big { - void looped::vehicle_jump() + class vehicle_jump : looped_command { - if (!g.vehicle.vehicle_jump) return; + using looped_command::looped_command; - const auto vehicle = self::veh; - - if (!vehicle || !ENTITY::IS_ENTITY_A_VEHICLE(vehicle)) + virtual void on_tick() override { - return; + if (self::veh && PAD::IS_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HANDBRAKE)) + { + ENTITY::APPLY_FORCE_TO_ENTITY(self::veh, 1, 0.0, 0.0, 20, 0.0, 0.0, 0.0, 0, 0, 1, 1, 0, 1); + } } + }; - if (PAD::IS_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_VEH_HANDBRAKE)) - { - ENTITY::APPLY_FORCE_TO_ENTITY(vehicle, 1, 0.0, 0.0, 20, 0.0, 0.0, 0.0, 0, 0, 1, 1, 0, 1); - } - } + vehicle_jump g_vehicle_jump("vehjump", "Vehicle Jump", "Makes the vehicle jump when you press the handbrake", g.vehicle.vehicle_jump); } diff --git a/src/backend/looped/weapons/force_crosshairs.cpp b/src/backend/looped/weapons/force_crosshairs.cpp index cc6a1316..6b33ae58 100644 --- a/src/backend/looped/weapons/force_crosshairs.cpp +++ b/src/backend/looped/weapons/force_crosshairs.cpp @@ -1,13 +1,17 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" -#include "core/enums.hpp" +#include "backend/looped_command.hpp" namespace big { - void looped::weapons_force_crosshairs() + class force_crosshairs : looped_command { - if (g.weapons.force_crosshairs) { + using looped_command::looped_command; + + virtual void on_tick() override + { HUD::SHOW_HUD_COMPONENT_THIS_FRAME(static_cast(HudComponents::RETICLE)); } - } -} \ No newline at end of file + }; + + force_crosshairs g_force_crosshairs("crosshairs", "Force Crosshairs", "Shows the crosshair even when you are not aiming", g.weapons.force_crosshairs); // do we need this? +} diff --git a/src/backend/looped/weapons/infinite_ammo.cpp b/src/backend/looped/weapons/infinite_ammo.cpp index 851918ec..a2418239 100644 --- a/src/backend/looped/weapons/infinite_ammo.cpp +++ b/src/backend/looped/weapons/infinite_ammo.cpp @@ -1,19 +1,25 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastInfiniteAmmo = false; - - void looped::weapons_infinite_ammo() + class infinite_ammo : looped_command { - bool bInfiniteAmmo = g.weapons.infinite_ammo; + using looped_command::looped_command; - if (bInfiniteAmmo || (!bInfiniteAmmo && bInfiniteAmmo != bLastInfiniteAmmo)) + CWeaponInfo* p_modified_weapon = nullptr; + float og_recoil_value = 0.0f; + + virtual void on_tick() override { - WEAPON::SET_PED_INFINITE_AMMO(self::ped, g.weapons.infinite_ammo, NULL); - - bLastInfiniteAmmo = g.weapons.infinite_ammo; + WEAPON::SET_PED_INFINITE_AMMO(self::ped, TRUE, NULL); } - } -} \ No newline at end of file + + virtual void on_disable() override + { + WEAPON::SET_PED_INFINITE_AMMO(self::ped, FALSE, NULL); + } + }; + + infinite_ammo g_infinite_ammo("infammo", "Infinite Ammo", "Never run out of ammo again", g.weapons.no_recoil); +} diff --git a/src/backend/looped/weapons/infinite_mag.cpp b/src/backend/looped/weapons/infinite_mag.cpp index 9e9885e9..59aa17f7 100644 --- a/src/backend/looped/weapons/infinite_mag.cpp +++ b/src/backend/looped/weapons/infinite_mag.cpp @@ -1,19 +1,25 @@ -#include "backend/looped/looped.hpp" #include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static bool bLastInfiniteMag = false; - - void looped::weapons_infinite_mag() + class infinite_mag : looped_command { - bool bInfiniteMag = g.weapons.infinite_mag; + using looped_command::looped_command; - if (bInfiniteMag || (!bInfiniteMag && bInfiniteMag != bLastInfiniteMag)) + CWeaponInfo* p_modified_weapon = nullptr; + float og_recoil_value = 0.0f; + + virtual void on_tick() override { - WEAPON::SET_PED_INFINITE_AMMO_CLIP(self::ped, g.weapons.infinite_mag); - - bLastInfiniteMag = g.weapons.infinite_mag; + WEAPON::SET_PED_INFINITE_AMMO_CLIP(self::ped, TRUE); } - } -} \ No newline at end of file + + virtual void on_disable() override + { + WEAPON::SET_PED_INFINITE_AMMO_CLIP(self::ped, FALSE); + } + }; + + infinite_mag g_infinite_mag("infclip", "Infinite Clip", "Shoot forever without needing to reload", g.weapons.no_recoil); +} diff --git a/src/backend/looped/weapons/no_recoil.cpp b/src/backend/looped/weapons/no_recoil.cpp index 41a3961c..a73e1f93 100644 --- a/src/backend/looped/weapons/no_recoil.cpp +++ b/src/backend/looped/weapons/no_recoil.cpp @@ -1,54 +1,47 @@ -#include "backend/looped/looped.hpp" -#include "pointers.hpp" +#include "gta/enums.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static std::vector> og_recoil_values{}; - static uint32_t prev_weapon_hash{}; - - bool is_recoil_value_cached(uint32_t hash) + class no_recoil : looped_command { - return std::find_if(og_recoil_values.begin(), og_recoil_values.end(), [hash](auto const entry) - { - return hash == entry.first; - }) != og_recoil_values.end(); - } + using looped_command::looped_command; - float get_og_recoil_value(uint32_t hash) - { - return std::find_if(og_recoil_values.begin(), og_recoil_values.end(), [hash](auto const entry) - { - return hash == entry.first; - })->second; - } + CWeaponInfo* p_modified_weapon = nullptr; + float og_recoil_value = 0.0f; - float get_recoil_value(uint32_t hash) - { - return g.weapons.no_recoil - ? 0.f - : get_og_recoil_value(hash); - } - - void looped::weapons_no_recoil() - { - if (!g_local_player) + virtual void on_tick() override { - return; - } - - auto* const weapon_mgr = g_local_player->m_weapon_manager; - if (weapon_mgr) - { - auto const cur_weapon_hash = weapon_mgr->m_selected_weapon_hash; - if (prev_weapon_hash != cur_weapon_hash) + if (!g_local_player) { - if (!is_recoil_value_cached(cur_weapon_hash)) + return; + } + + auto* const weapon_mgr = g_local_player->m_weapon_manager; + if (weapon_mgr) + { + if (p_modified_weapon != weapon_mgr->m_weapon_info && weapon_mgr->m_weapon_info) { - og_recoil_values.push_back({ cur_weapon_hash, weapon_mgr->m_weapon_info->m_explosion_shake_amplitude }); + if (p_modified_weapon) + p_modified_weapon->m_explosion_shake_amplitude = og_recoil_value; + + og_recoil_value = weapon_mgr->m_weapon_info->m_explosion_shake_amplitude; + p_modified_weapon = weapon_mgr->m_weapon_info; + weapon_mgr->m_weapon_info->m_explosion_shake_amplitude = 0.0f; } - - weapon_mgr->m_weapon_info->m_explosion_shake_amplitude = get_recoil_value(cur_weapon_hash); // m_explosion_shake_amplitude is the right offset in https://github.com/Yimura/GTAV-Classes } } - } -} \ No newline at end of file + + virtual void on_disable() override + { + if (g_local_player && p_modified_weapon) + { + p_modified_weapon->m_explosion_shake_amplitude = og_recoil_value; + p_modified_weapon = nullptr; + } + } + }; + + no_recoil g_no_recoil("norecoil", "No Recoil", "Removes weapon recoil when shooting", g.weapons.no_recoil); +} diff --git a/src/backend/looped/weapons/no_spread.cpp b/src/backend/looped/weapons/no_spread.cpp index 5ca736aa..a5d51b1d 100644 --- a/src/backend/looped/weapons/no_spread.cpp +++ b/src/backend/looped/weapons/no_spread.cpp @@ -1,54 +1,47 @@ -#include "backend/looped/looped.hpp" -#include "pointers.hpp" +#include "gta/enums.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" namespace big { - static std::vector> og_spread_values{}; - static uint32_t prev_weapon_hash{}; + class no_spread : looped_command + { + using looped_command::looped_command; - bool is_spread_value_cached(uint32_t hash) - { - return std::find_if(og_spread_values.begin(), og_spread_values.end(), [hash](auto const entry) + CWeaponInfo* p_modified_weapon = nullptr; + float og_spread_value = 0.0f; + + virtual void on_tick() override + { + if (!g_local_player) { - return hash == entry.first; - }) != og_spread_values.end(); - } + return; + } - float get_og_spread_value(uint32_t hash) - { - return std::find_if(og_spread_values.begin(), og_spread_values.end(), [hash](auto const entry) + auto* const weapon_mgr = g_local_player->m_weapon_manager; + if (weapon_mgr) { - return hash == entry.first; - })->second; - } - - float get_spread_value(uint32_t hash) - { - return g.weapons.no_spread - ? 0.f - : get_og_spread_value(hash); - } - - void looped::weapons_no_spread() - { - if (!g_local_player) - { - return; - } - - auto* const weapon_mgr = g_local_player->m_weapon_manager; - if (weapon_mgr) - { - auto const cur_weapon_hash = weapon_mgr->m_selected_weapon_hash; - if (prev_weapon_hash != cur_weapon_hash) - { - if (!is_spread_value_cached(cur_weapon_hash)) + if (p_modified_weapon != weapon_mgr->m_weapon_info && weapon_mgr->m_weapon_info) { - og_spread_values.push_back({ cur_weapon_hash, weapon_mgr->m_weapon_info->m_accuracy_spread }); - } + if (p_modified_weapon) + p_modified_weapon->m_accuracy_spread = og_spread_value; - weapon_mgr->m_weapon_info->m_accuracy_spread = get_spread_value(cur_weapon_hash); + og_spread_value = weapon_mgr->m_weapon_info->m_accuracy_spread; + p_modified_weapon = weapon_mgr->m_weapon_info; + weapon_mgr->m_weapon_info->m_accuracy_spread = 0.0f; + } + } + } + + virtual void on_disable() override + { + if (g_local_player && p_modified_weapon) + { + p_modified_weapon->m_accuracy_spread = og_spread_value; + p_modified_weapon = nullptr; } } - } -} \ No newline at end of file + }; + + no_spread g_no_spread("nospread", "No Spread", "Removes weapon spread when shooting", g.weapons.no_spread); +} diff --git a/src/backend/looped/weapons/rapid_fire.cpp b/src/backend/looped/weapons/rapid_fire.cpp index 30bbfa81..b5a7d71c 100644 --- a/src/backend/looped/weapons/rapid_fire.cpp +++ b/src/backend/looped/weapons/rapid_fire.cpp @@ -1,16 +1,18 @@ -#include "backend/looped/looped.hpp" -#include "natives.hpp" #include "gta/enums.hpp" +#include "natives.hpp" +#include "backend/looped_command.hpp" #include "util/math.hpp" #include "gui.hpp" namespace big { - void looped::weapons_rapid_fire() - { - if (g.weapons.rapid_fire) - { - if(!HUD::IS_PAUSE_MENU_ACTIVE() && !g_gui->is_open() && !PED::IS_PED_DEAD_OR_DYING(self::ped, true)) + class rapid_fire : looped_command + { + using looped_command::looped_command; + + virtual void on_tick() override + { + if (!HUD::IS_PAUSE_MENU_ACTIVE() && !g_gui->is_open() && !PED::IS_PED_DEAD_OR_DYING(self::ped, true) && !PED::IS_PED_IN_ANY_VEHICLE(self::ped, TRUE)) { if (PAD::IS_DISABLED_CONTROL_PRESSED(0, (int)ControllerInputs::INPUT_ATTACK)) { @@ -22,6 +24,8 @@ namespace big MISC::SHOOT_SINGLE_BULLET_BETWEEN_COORDS(start.x, start.y, start.z, end.x, end.y, end.z, WEAPON::GET_WEAPON_DAMAGE(weapon_hash, 0), true, weapon_hash, self::ped, true, false, -1.0); } } - } - } -} \ No newline at end of file + } + }; + + rapid_fire g_rapid_fire("rapidfire", "Rapid Fire", "Makes your weapon fire insanely fast", g.weapons.rapid_fire); +} diff --git a/src/backend/looped_command.cpp b/src/backend/looped_command.cpp new file mode 100644 index 00000000..2926674b --- /dev/null +++ b/src/backend/looped_command.cpp @@ -0,0 +1,45 @@ +#include "looped_command.hpp" +#include "fiber_pool.hpp" + +namespace big +{ + looped_command::looped_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle) : + bool_command(name, label, description, toggle) + { + g_looped_commands.push_back(this); + } + + void looped_command::enable() + { + if (!m_toggle) + { + m_toggle = true; + m_last_enabled = true; + g_fiber_pool->queue_job([this] { on_enable(); }); + } + } + + void looped_command::disable() + { + if (m_toggle) + { + m_toggle = false; + m_last_enabled = false; + g_fiber_pool->queue_job([this] { disable(); }); + } + } + + void looped_command::refresh() + { + if (m_toggle && !m_last_enabled) + { + m_last_enabled = true; + g_fiber_pool->queue_job([this] { on_enable(); }); + } + else if (!m_toggle && m_last_enabled) + { + m_last_enabled = false; + g_fiber_pool->queue_job([this] { on_disable(); }); + } + } +} \ No newline at end of file diff --git a/src/backend/looped_command.hpp b/src/backend/looped_command.hpp new file mode 100644 index 00000000..19822990 --- /dev/null +++ b/src/backend/looped_command.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "bool_command.hpp" + +namespace big +{ + class looped_command : public bool_command + { + bool m_last_enabled = false; + + public: + looped_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle); + + virtual void on_enable() {}; + virtual void on_disable() {}; + virtual void on_tick() = 0; + + virtual void refresh() override; + virtual void enable() override; + virtual void disable() override; + }; + + inline std::vector g_looped_commands; +} \ No newline at end of file diff --git a/src/backend/player_command.cpp b/src/backend/player_command.cpp new file mode 100644 index 00000000..f3601039 --- /dev/null +++ b/src/backend/player_command.cpp @@ -0,0 +1,133 @@ +#include "player_command.hpp" +#include "fiber_pool.hpp" + +namespace big +{ + player_all_component::player_all_component(player_command* parent, const std::string& name, const std::string& label, const std::string& description, std::optional num_args) : + command(name + "all", label, description, num_args), + m_parent(parent) + { + } + + void player_all_component::execute(const std::vector& args, const std::shared_ptr ctx) + { + g_fiber_pool->queue_job([this, args, &ctx] + { + g_player_service->iterate([this, args, &ctx](const player_entry& player) + { + m_parent->execute(player.second, args, ctx); + }); + }); + } + + std::optional> player_all_component::parse_args(const std::vector& args, const std::shared_ptr ctx) + { + return m_parent->parse_args_p(args, ctx); + } + + player_command::player_command(const std::string& name, const std::string& label, const std::string& description, std::optional num_args, bool make_all_version) : + command(name, label, description, num_args.has_value() ? std::optional{num_args.value() + 1} : std::nullopt) + { + if (make_all_version) + m_all_component = std::make_unique(this, name, label, description, num_args); + } + + void player_command::execute(const std::vector& args, const std::shared_ptr ctx) + { + g_fiber_pool->queue_job([this, args, ctx] + { + std::vector new_args; + + // TODO: This looks ugly and inefficient + for (int i = 1; i < m_num_args; i++) + new_args.push_back(args[i]); + + if (g_player_service->get_self()->id() == args[0]) + { + execute(g_player_service->get_self(), new_args, ctx); + return; + } + + for (auto& plyr : g_player_service->players()) + { + if (plyr.second->id() == args[0]) + { + execute(plyr.second, new_args, ctx); + return; + } + } + + ctx->report_error(std::format("Tried to execute command {}, but a player with index {} was not found", m_name, args[0])); + }); + } + + std::optional> player_command::parse_args(const std::vector& args, const std::shared_ptr ctx) + { + std::vector new_args; + std::vector result; + + if (args[0] == "me" || args[0] == "self") + { + result.push_back(ctx->get_sender()->id()); + } + else + { + int plyr_id = -1; + + for (auto& plyr : g_player_service->players()) + { + if (stricmp(plyr.second->get_name(), args[0].c_str()) == 0) + { + plyr_id = plyr.second->id(); + break; + } + } + + if (stricmp(g_player_service->get_self()->get_name(), args[0].c_str()) == 0 || (g.spoofing.spoof_username && stricmp(g.spoofing.username.c_str(), args[0].c_str()) == 0)) + { + plyr_id = g_player_service->get_self()->id(); + } + + if (ctx->get_access_level() != CommandAccessLevel::ADMIN && (get_access_level() == CommandAccessLevel::TOXIC || get_access_level() == CommandAccessLevel::AGGRESSIVE) && plyr_id == self::id) + { + ctx->report_error("Permission denied, cannot call toxic commands on me"); + return std::nullopt; + } + + if (plyr_id == -1) + { + ctx->report_error(std::format("Cannot find player with name {} in command {}", args[0], m_name)); + return std::nullopt; + } + + result.push_back(plyr_id); + } + + for (int i = 1; i < args.size(); i++) + new_args.push_back(args[i]); + + auto res = parse_args_p(new_args, ctx); + if (!res.has_value()) + return std::nullopt; + + for (auto& p : res.value()) + result.push_back(p); + + return result; + } + + void player_command::call(player_ptr player, const std::vector& args, const std::shared_ptr ctx) + { + // TODO: Code duplication + if (m_num_args.has_value() && args.size() != (m_num_args.value() - 1)) + { + ctx->report_error(std::format("Command {} called with the wrong number of arguments. Expected {}, got {}", m_name, m_num_args.value(), args.size())); + return; + } + + g_fiber_pool->queue_job([this, player, args, ctx] { + if (player->is_valid()) + execute(player, args, ctx); + }); + } +} \ No newline at end of file diff --git a/src/backend/player_command.hpp b/src/backend/player_command.hpp new file mode 100644 index 00000000..b6a4991c --- /dev/null +++ b/src/backend/player_command.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "command.hpp" +#include "services/players/player_service.hpp" + +namespace big +{ + class player_command; + + class player_all_component : public command + { + player_command* m_parent; + protected: + virtual void execute(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + public: + player_all_component(player_command* parent, const std::string& name, const std::string& label, const std::string& description, std::optional num_args); + }; + + class player_command : public command + { + friend player_all_component; + std::unique_ptr m_all_component; + + protected: + virtual void execute(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + virtual void execute(player_ptr player, const std::vector& args, const std::shared_ptr ctx = std::make_shared()) = 0; + virtual std::optional> parse_args(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) override; + virtual std::optional> parse_args_p(const std::vector& args, const std::shared_ptr ctx = std::make_shared()) { return std::vector(); }; + public: + void call(player_ptr player, const std::vector& args, const std::shared_ptr ctx = std::make_shared()); + player_command(const std::string& name, const std::string& label, const std::string& description, std::optional num_args, bool make_all_version = true); + }; +} \ No newline at end of file diff --git a/src/backend/script_patches.hpp b/src/backend/script_patches.hpp index 6d8e52a7..b8073526 100644 --- a/src/backend/script_patches.hpp +++ b/src/backend/script_patches.hpp @@ -12,6 +12,7 @@ namespace big g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "5D ? ? ? 76 57 ? ? 5D ? ? ? 76", 0, { 0x2E, 0x00, 0x00 }, nullptr }); // end session kick protection g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "71 2E ? ? 55 ? ? 61 ? ? ? 47 ? ? 63", 0, { 0x72 }, nullptr }); // load island even if stranded animal IPL choice is not set + g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 00 07 00 00 7B", 5, { 0x2E, 0x00, 0x00 }, nullptr }); // disable population load balancing g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, { 0x71, 0x2E, 0x01, 0x01 }, nullptr }); // despawn bypass g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "38 00 5D ? ? ? 38 00 5D ? ? ? 38 00 41", 0, std::vector(12, 0x0), nullptr}); // godmode/invisibility detection bypass diff --git a/src/core/data/bullet_impact_types.hpp b/src/core/data/bullet_impact_types.hpp index 40735f87..22dad29d 100644 --- a/src/core/data/bullet_impact_types.hpp +++ b/src/core/data/bullet_impact_types.hpp @@ -1,6 +1,7 @@ #pragma once -std::map BULLET_IMPACTS = { +inline std::unordered_map BULLET_IMPACTS = +{ { eExplosionTag::DONTCARE, "DEFAULT_BULLETS" }, { eExplosionTag::GRENADE, "GRENADE" }, { eExplosionTag::GRENADELAUNCHER, "GRENADELAUNCHER" }, diff --git a/src/core/data/command_access_levels.hpp b/src/core/data/command_access_levels.hpp new file mode 100644 index 00000000..347b4a7b --- /dev/null +++ b/src/core/data/command_access_levels.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "core/enums.hpp" + +namespace big +{ + inline std::unordered_map COMMAND_ACCESS_LEVELS = + { + { CommandAccessLevel::NONE, "None" }, + { CommandAccessLevel::FRIENDLY, "Friendly" }, + { CommandAccessLevel::AGGRESSIVE, "Aggressive" }, + { CommandAccessLevel::TOXIC, "Toxic" }, + { CommandAccessLevel::ADMIN, "Admin (!)" } + }; +} \ No newline at end of file diff --git a/src/core/enums.hpp b/src/core/enums.hpp index 43b3852a..c7201d7e 100644 --- a/src/core/enums.hpp +++ b/src/core/enums.hpp @@ -399,4 +399,20 @@ namespace big HUD_COMPONENTS, HUD_WEAPONS }; + + enum class CommandAccessLevel + { + NONE, + FRIENDLY, // heal, semi godmode... + AGGRESSIVE, // kick from vehicle, send to apartment... + TOXIC, // kicks + ADMIN // full access + }; + NLOHMANN_JSON_SERIALIZE_ENUM(CommandAccessLevel, { + { CommandAccessLevel::NONE, "none" }, + { CommandAccessLevel::FRIENDLY, "friendly" }, + { CommandAccessLevel::AGGRESSIVE, "aggressive" }, + { CommandAccessLevel::TOXIC, "toxic" }, + { CommandAccessLevel::ADMIN, "admin" } + }) } diff --git a/src/core/globals.hpp b/src/core/globals.hpp index 97aac08b..1a2bcb04 100644 --- a/src/core/globals.hpp +++ b/src/core/globals.hpp @@ -305,6 +305,12 @@ namespace big std::string spoofed_name = ""; bool join_in_sctv_slots = false; + const char chat_command_prefix = '/'; + const char chat_output_prefix = '>'; + + bool chat_commands = false; + CommandAccessLevel chat_command_default_access_level = CommandAccessLevel::FRIENDLY; + bool kick_chat_spammers = false; bool kick_host_when_forcing_host = false; @@ -334,7 +340,8 @@ namespace big log_text_messages, decloak_players, force_session_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, name_spoof_enabled, advertise_menu, spoofed_name, join_in_sctv_slots, kick_chat_spammers, kick_host_when_forcing_host, explosion_karma, damage_karma, disable_traffic, - disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, send_to_apartment_idx, send_to_warehouse_idx) + disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, send_to_apartment_idx, send_to_warehouse_idx, + chat_commands, chat_command_default_access_level) } session{}; struct settings @@ -482,7 +489,7 @@ namespace big bool drive_on_water = false; bool horn_boost = false; bool instant_brake = false; - bool is_targetable = true; + bool block_homing = true; bool ls_customs = false; // don't save this to disk bool seatbelt = false; bool turn_signals = false; @@ -496,7 +503,7 @@ namespace big speedo_meter, fly, rainbow_paint, speed_unit, god_mode, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_water, proof_mask, auto_drive_destination, auto_drive_style, auto_drive_speed, auto_turn_signals, boost_behavior, - drive_on_water, horn_boost, instant_brake, is_targetable, seatbelt, turn_signals, vehicle_jump, + drive_on_water, horn_boost, instant_brake, block_homing, seatbelt, turn_signals, vehicle_jump, keep_vehicle_repaired, no_water_collision, disable_engine_auto_start, change_engine_state_immediately) } vehicle{}; diff --git a/src/function_types.hpp b/src/function_types.hpp index 0def2562..82b4750a 100644 --- a/src/function_types.hpp +++ b/src/function_types.hpp @@ -98,7 +98,7 @@ namespace big::functions using generate_uuid = bool(*)(std::uint64_t* uuid); - using send_chat_message = bool(*)(int64_t* send_chat_ptr, rage::rlGamerInfo* game_info, char* message, bool is_team); + using send_chat_message = bool(*)(int64_t* send_chat_ptr, rage::rlGamerInfo* gamer_info, char* message, bool is_team); using send_network_damage = void(*)(CEntity* source, CEntity* target, rage::fvector3* position, int hit_component, bool override_default_damage, int weapon_type, float override_damage, int tire_index, int suspension_index, int flags, std::uint32_t action_result_hash, std::int16_t action_result_id, int action_unk, bool hit_weapon, bool hit_weapon_ammo_attachment, bool silenced, bool unk, rage::fvector3* impact_direction); diff --git a/src/gta/joaat.hpp b/src/gta/joaat.hpp index 10cb4a0c..7444599d 100644 --- a/src/gta/joaat.hpp +++ b/src/gta/joaat.hpp @@ -8,26 +8,25 @@ namespace rage { - template - struct constexpr_joaat { - char data[CharCount]; - template - constexpr constexpr_joaat(const char *str, std::index_sequence) : data{ (str[Indices])... } {} - constexpr joaat_t operator()() + inline consteval joaat_t consteval_joaat(const std::span& data) + { + joaat_t hash = 0; + + for (std::size_t i = 0; i < data.size() - 1; ++i) { - joaat_t hash = 0; - for (std::size_t i = 0; i < CharCount; ++i) { - hash += joaat_to_lower(data[i]); - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; + hash += joaat_to_lower(data[i]); + hash += (hash << 10); + hash ^= (hash >> 6); } - }; + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; + } + static_assert(consteval_joaat("test") == 0x3f75ccc1); } -#define RAGE_JOAAT_IMPL(str) (::rage::constexpr_joaat((str), std::make_index_sequence())()) +#define RAGE_JOAAT_IMPL(str) (::rage::consteval_joaat(str)) #define RAGE_JOAAT(str) (std::integral_constant::value) \ No newline at end of file diff --git a/src/gui/components/components.hpp b/src/gui/components/components.hpp index 2d174e46..66e6f5e3 100644 --- a/src/gui/components/components.hpp +++ b/src/gui/components/components.hpp @@ -1,5 +1,8 @@ #pragma once #include "imgui.h" +#include "backend/command.hpp" +#include "backend/looped_command.hpp" +#include "backend/player_command.hpp" namespace big { @@ -27,5 +30,40 @@ namespace big static void selectable(const std::string_view, bool, ImGuiSelectableFlags, std::function); static bool script_patch_checkbox(const std::string_view text, bool* option, const std::string_view tooltip = ""); + + template + struct template_str + { + constexpr template_str(const char(&str)[N]) + { + std::copy_n(str, N, value); + } + + char value[N]; + }; + + template + static void command_button(const std::vector args = {}, std::optional label_override = std::nullopt) + { + static command* command = command::get(rage::consteval_joaat(cmd_str.value)); + if (ImGui::Button(label_override.value_or(command->get_label()).data())) + command->call(args); + } + + template + static void player_command_button(player_ptr player = g_player_service->get_selected(), const std::vector args = {}, std::optional label_override = std::nullopt) + { + static player_command* command = (player_command*)command::get(rage::consteval_joaat(cmd_str.value)); + if (ImGui::Button(label_override.value_or(command->get_label()).data())) + command->call(player, args); + } + + template + static void command_checkbox(std::optional label_override = std::nullopt) + { + static bool_command* command = (bool_command*)command::get(rage::consteval_joaat(cmd_str.value)); + if (ImGui::Checkbox(label_override.value_or(command->get_label()).data(), &command->is_enabled())) + command->refresh(); + } }; } diff --git a/src/hooking.cpp b/src/hooking.cpp index e7ce8226..1973278d 100644 --- a/src/hooking.cpp +++ b/src/hooking.cpp @@ -77,6 +77,7 @@ namespace big detour_hook_helper::add("SSD", g_pointers->m_sort_session_details); detour_hook_helper::add("APTS", g_pointers->m_add_player_to_session); + detour_hook_helper::add("SCM", g_pointers->m_send_chat_message); detour_hook_helper::add("SCNM", g_pointers->m_send_chat_net_message); detour_hook_helper::add("PMFR", g_pointers->m_process_matchmaking_find_response); diff --git a/src/hooking.hpp b/src/hooking.hpp index 621531be..25f2c462 100644 --- a/src/hooking.hpp +++ b/src/hooking.hpp @@ -111,6 +111,7 @@ namespace big static bool add_player_to_session(rage::netConnectionManager* mgr, int receiver_msg_id, int* out_command_hndl, RemoteGamerInfoMsg* msg, int flags, void* unk); static bool send_chat_net_message(rage::netConnectionManager* mgr, int receiver_msg_id, CMsgTextMessage* msg, int flags, void* unk); + static bool send_chat_message(void* team_mgr, rage::rlGamerInfo* local_gamer_info, char* message, bool is_team); static bool process_matchmaking_find_response(void* _this, void* unused, rage::JSONNode* node, int* unk); diff --git a/src/hooks/misc/send_chat_message.cpp b/src/hooks/misc/send_chat_message.cpp new file mode 100644 index 00000000..252ef04d --- /dev/null +++ b/src/hooks/misc/send_chat_message.cpp @@ -0,0 +1,17 @@ +#include "hooking.hpp" +#include "gta_util.hpp" +#include "services/players/player_service.hpp" + +#include "backend/command.hpp" +#include "backend/context/chat_command_context.hpp" + +namespace big +{ + bool hooks::send_chat_message(void* team_mgr, rage::rlGamerInfo* local_gamer_info, char* message, bool is_team) + { + if (g.session.chat_commands && message[0] == g.session.chat_command_prefix) + command::process(std::string(message + 1), std::make_shared(g_player_service->get_self())); + + return g_hooking->get_original()(team_mgr, local_gamer_info, message, is_team); + } +} \ No newline at end of file diff --git a/src/hooks/protections/receive_net_message.cpp b/src/hooks/protections/receive_net_message.cpp index 3ab5e447..54d3c72e 100644 --- a/src/hooks/protections/receive_net_message.cpp +++ b/src/hooks/protections/receive_net_message.cpp @@ -4,7 +4,12 @@ #include "gta_util.hpp" #include "util/session.hpp" #include "util/spam.hpp" -#include "util/kick.hpp" +#include "backend/command.hpp" +#include "backend/context/chat_command_context.hpp" +#include "gta/net_game_event.hpp" +#include "gta/script_id.hpp" +#include "backend/player_command.hpp" + #include #include @@ -85,13 +90,18 @@ namespace big spam::log_chat(message, player, true); player->is_spammer = true; if (g.session.kick_chat_spammers) - kick::breakup_kick(player); + { + ((player_command*)command::get(RAGE_JOAAT("breakup")))->call(player, {}); + } return true; } else { if (g.session.log_chat_messages) spam::log_chat(message, player, false); + + if (g.session.chat_commands && message[0] == g.session.chat_command_prefix) + command::process(std::string(message + 1), std::make_shared(player)); } break; } @@ -131,8 +141,17 @@ namespace big if (player && pl && player->id() != pl->id() && count == 1 && frame->m_msg_id == -1) { - g_notification_service->push_error("Warning!", std::format("{} breakup kicked {}!", player->get_name(), pl->get_name())); - session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED); + if (g_player_service->get_self()->is_host()) + { + g_notification_service->push_error("Warning!", std::format("{} tried to breakup kick {}!", player->get_name(), pl->get_name())); + session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED); + return true; + } + else + { + g_notification_service->push_error("Warning!", std::format("{} breakup kicked {}!", player->get_name(), pl->get_name())); + session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED); + } } break; diff --git a/src/hooks/protections/script_event_handler.cpp b/src/hooks/protections/script_event_handler.cpp index 5e5d16d7..b622a0a4 100644 --- a/src/hooks/protections/script_event_handler.cpp +++ b/src/hooks/protections/script_event_handler.cpp @@ -26,14 +26,6 @@ namespace big const auto& notify = g.notifications.script_event_handler; - // detect pasted menus setting args[1] to something other than PLAYER_ID() - if (*(int*)&args[1] != player->m_player_id && player->m_player_id != -1) - { - LOG(INFO) << "Hash = " << (int)args[0]; - format_string(player_name, "TSE sender mismatch", notify.tse_sender_mismatch.log, notify.tse_sender_mismatch.notify); - return true; - } - switch (hash) { case eRemoteEvent::Bounty: @@ -343,6 +335,14 @@ namespace big break; } + // detect pasted menus setting args[1] to something other than PLAYER_ID() + if (*(int*)&args[1] != player->m_player_id && player->m_player_id != -1) + { + LOG(INFO) << "Hash = " << (int)args[0]; + format_string(player_name, "TSE sender mismatch", notify.tse_sender_mismatch.log, notify.tse_sender_mismatch.notify); + return true; + } + if (g.debug.logs.script_event.logs && (!g.debug.logs.script_event.filter_player || g.debug.logs.script_event.player_id == player->m_player_id)) { std::string script_args = "{ "; diff --git a/src/json_util.hpp b/src/json_util.hpp index 4ee15127..b84579ad 100644 --- a/src/json_util.hpp +++ b/src/json_util.hpp @@ -5,7 +5,7 @@ namespace big template static inline void set_from_key_or_default(const nlohmann::json& j, const char* key, ValueType& value, ValueType default_value = {}) { - if (j.contains(key)) + if (j.contains(key) && !j[key].is_null()) { j.at(key).get_to(value); } diff --git a/src/main.cpp b/src/main.cpp index 49b5d80d..5cb26fb6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,7 +104,6 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) g_script_mgr.add_script(std::make_unique