diff --git a/src/backend/commands/player/toxic/start_script.cpp b/src/backend/commands/player/toxic/start_script.cpp index 540556cf..b926cc92 100644 --- a/src/backend/commands/player/toxic/start_script.cpp +++ b/src/backend/commands/player/toxic/start_script.cpp @@ -44,13 +44,14 @@ namespace big } }; + // Scripts should be up-to-date as of 5/5/2024 start_script<20> g_start_tutorial("tutorial", "BACKEND_START_SCRIPT_START_TUTORIAL", "BACKEND_START_SCRIPT_START_TUTORIAL_DESC", 0); start_script<200> g_start_golf("golf", "BACKEND_START_SCRIPT_START_GOLF", "BACKEND_START_SCRIPT_START_GOLF_DESC", 0); start_script<203> g_start_flight_school("flightschool", "BACKEND_START_SCRIPT_START_FLIGHT_SCHOOL", "BACKEND_START_SCRIPT_START_FLIGHT_SCHOOL_DESC", 0); start_script<9> g_start_darts("darts", "BACKEND_START_SCRIPT_START_DARTS", "BACKEND_START_SCRIPT_START_DARTS_DESC", 0); - start_script<218> g_start_badlands("badlands", "BACKEND_START_SCRIPT_START_BADLANDS_REVENGE_II", "BACKEND_START_SCRIPT_START_BADLANDS_REVENGE_II_DESC", 0); - start_script<223> g_start_space_monkey("spacemonkey", "BACKEND_START_SCRIPT_START_SPACE_MONKEY", "BACKEND_START_SCRIPT_START_SPACE_MONKEY_DESC", 0); - start_script<219> g_start_wizards_ruin("wizard", "BACKEND_START_SCRIPT_START_WIZARD", "BACKEND_START_SCRIPT_START_WIZARD_DESC", 0); - start_script<224> g_start_qub3d("qub3d", "BACKEND_START_SCRIPT_START_QUB3D", "BACKEND_START_SCRIPT_START_QUB3D_DESC", 0); - start_script<225> g_start_camhedz("camhedz", "BACKEND_START_SCRIPT_START_CAMHEDZ", "BACKEND_START_SCRIPT_START_CAMHEDZ_DESC", 0); + start_script<230> g_start_badlands("badlands", "BACKEND_START_SCRIPT_START_BADLANDS_REVENGE_II", "BACKEND_START_SCRIPT_START_BADLANDS_REVENGE_II_DESC", 0); + start_script<235> g_start_space_monkey("spacemonkey", "BACKEND_START_SCRIPT_START_SPACE_MONKEY", "BACKEND_START_SCRIPT_START_SPACE_MONKEY_DESC", 0); + start_script<231> g_start_wizards_ruin("wizard", "BACKEND_START_SCRIPT_START_WIZARD", "BACKEND_START_SCRIPT_START_WIZARD_DESC", 0); + start_script<236> g_start_qub3d("qub3d", "BACKEND_START_SCRIPT_START_QUB3D", "BACKEND_START_SCRIPT_START_QUB3D_DESC", 0); // puzzle? + start_script<237> g_start_camhedz("camhedz", "BACKEND_START_SCRIPT_START_CAMHEDZ", "BACKEND_START_SCRIPT_START_CAMHEDZ_DESC", 0); } \ No newline at end of file diff --git a/src/backend/reactions/reaction.cpp b/src/backend/reactions/reaction.cpp index 08603cdf..57952055 100644 --- a/src/backend/reactions/reaction.cpp +++ b/src/backend/reactions/reaction.cpp @@ -77,4 +77,27 @@ namespace big process_common(player); } + + // This function provides the same notification capabilities as process, but without further kick/timeout actions + // Probably no point announcing to chat, either + void reaction::only_notify(player_ptr player) + { + if (!player->is_valid()) + return; + if ((player->is_friend() && g.session.trust_friends) || player->is_trusted || g.session.trust_session) + return; + + if (log) + { + uint64_t rockstar_id = player->get_net_data() == nullptr ? 0 : player->get_net_data()->m_gamer_handle.m_rockstar_id; + LOGF(WARNING, "Received {} from {} ({})", m_event_name, player->get_name(), rockstar_id); + } + + if (notify) + { + // Use a different notification since the default start_script reaction is "Blocked Start Script" + g_notification_service.push_warning("PROTECTIONS"_T.data(), + std::vformat("REACTION_START_SCRIPT_ALLOWED"_T.data(), std::make_format_args(player->get_name()))); + } + } } diff --git a/src/backend/reactions/reaction.hpp b/src/backend/reactions/reaction.hpp index 7d2d6583..11631129 100644 --- a/src/backend/reactions/reaction.hpp +++ b/src/backend/reactions/reaction.hpp @@ -25,6 +25,7 @@ namespace big reaction(const char* event_name, const char* notify_message, const char* announce_message); virtual void process(player_ptr player); + virtual void only_notify(player_ptr player); virtual void process_common(player_ptr player); }; } \ No newline at end of file diff --git a/src/hooks/protections/script_event_handler.cpp b/src/hooks/protections/script_event_handler.cpp index c5f8e477..0e8c14e5 100644 --- a/src/hooks/protections/script_event_handler.cpp +++ b/src/hooks/protections/script_event_handler.cpp @@ -6,6 +6,7 @@ #include "lua/lua_manager.hpp" #include "util/math.hpp" #include "util/session.hpp" +#include "util/script_database.hpp" #include #include @@ -14,6 +15,8 @@ namespace big { + static const script_protection_DB script_database; + void format_string(std::string_view player_name, std::string_view protection_type, bool should_log, bool should_notify) { if (should_log) @@ -420,18 +423,27 @@ namespace big } case eRemoteEvent::StartScriptBegin: { - static const std::unordered_set bad_script_ids = { - 17 /*AM_PI_MENU*/, 20 /*fm_intro*/, 212 /*golf_mp*/, 214 /*tennis_network_mp*/, - 215 /*Pilot_School_MP*/, 216 /*FM_Impromptu_DM_Controler*/, 217 /*fm_Bj_race_controler*/, 218 /*fm_deathmatch_controler*/, - 221 /*FM_Race_Controler*/, 222 /*FM_Horde_Controler*/, 226 /*grid_arcade_cabinet*/, 227 /*scroll_arcade_cabinet*/, - 229 /*road_arcade*/, 231 /*wizard_arcade*/, 235 /*ggsm_arcade*/, 236 /*puzzle*/, 238 /*SCTV*/ }; auto script_id = args[3]; - if (bad_script_ids.contains(script_id)) + + protection_status protection_status = script_database.get_protection_status(script_id); + + if (protection_status == protection_status::BLOCK_ALWAYS) { g.reactions.start_script.process(plyr); return true; } - break; + + if (!NETWORK::NETWORK_IS_ACTIVITY_SESSION() && protection_status == protection_status::BLOCK_IN_FREEMODE) + { + g.reactions.start_script.process(plyr); + return true; + } + + if (protection_status == protection_status::ALLOWED_NOTIFY) + { + g.reactions.start_script.only_notify(plyr); + } + } } diff --git a/src/native_hooks/am_launcher.hpp b/src/native_hooks/am_launcher.hpp index 9f0c4dc5..583dbb57 100644 --- a/src/native_hooks/am_launcher.hpp +++ b/src/native_hooks/am_launcher.hpp @@ -4,18 +4,10 @@ namespace big { namespace am_launcher { - static const std::unordered_set bad_script_hashes = {"ggsm_arcade"_J, "camhedz_arcade"_J, "wizard_arcade"_J, "puzzle"_J, "fm_intro"_J, "pilot_school_mp"_J, "golf_mp"_J, "tennis_network_mp"_J, "fm_race_controler"_J, "fm_horde_controler"_J, "fm_mission_controller"_J, "fm_mission_controller_2020"_J, "fm_impromptu_dm_controler"_J, "fm_deathmatch_controler"_J, "fm_bj_race_controler"_J, "fm_survival_controller"_J, "sctv"_J, "am_pi_menu"_J, "scroll_arcade_cabinet"_J, "grid_arcade_cabinet"_J, "degenatron_games"_J, "gunslinger_arcade"_J, "road_arcade"_J, "AM_MP_DRONE"_J}; - static void START_NEW_SCRIPT_WITH_ARGS(rage::scrNativeCallContext* src) { const char* const name = src->get_arg(0); - if (bad_script_hashes.contains(rage::joaat(name))) - { - src->set_return_value(0); - return; - } - Any* args = src->get_arg(1); const int argc = src->get_arg(2); const int stackSize = src->get_arg(3); diff --git a/src/util/script_database.hpp b/src/util/script_database.hpp new file mode 100644 index 00000000..c1c0d27f --- /dev/null +++ b/src/util/script_database.hpp @@ -0,0 +1,78 @@ +#include +#include + +namespace big +{ + enum class protection_status + { + ALLOWED_NOTIFY, + BLOCK_ALWAYS, + BLOCK_IN_FREEMODE + }; + + struct script_info + { + std::string name; + protection_status status; + }; + + class script_protection_DB + { + public: + script_protection_DB() + { + initialize_script_DB(); + } + + protection_status get_protection_status(int scriptId) const + { + auto it = m_script_map.find(scriptId); + if (it != m_script_map.end()) + { + return it->second.status; + } + return protection_status::ALLOWED_NOTIFY; + } + + // Could be useful for debugging someday... + std::string get_script_name(int scriptId) const + { + auto it = m_script_map.find(scriptId); + if (it != m_script_map.end()) + { + return it->second.name; + } + return ""; + } + + private: + std::unordered_map m_script_map; + + void initialize_script_DB() + { + // Please try to keep this in numerical order for code readability + // Last script ID update 5/5/2024 + m_script_map = {{9, {"AM_Darts", protection_status::BLOCK_ALWAYS}}, + {17, {"AM_PI_MENU", protection_status::BLOCK_ALWAYS}}, + {20, {"fm_intro", protection_status::BLOCK_ALWAYS}}, + {212, {"golf_mp", protection_status::BLOCK_IN_FREEMODE}}, + {214, {"tennis_network_mp", protection_status::BLOCK_IN_FREEMODE}}, + {215, {"Pilot_School_MP", protection_status::BLOCK_ALWAYS}}, + {216, {"FM_Impromptu_DM_Controler", protection_status::BLOCK_IN_FREEMODE}}, + {218, {"fm_deathmatch_controler", protection_status::BLOCK_IN_FREEMODE}}, + {221, {"FM_Race_Controler", protection_status::BLOCK_IN_FREEMODE}}, + {222, {"FM_Horde_Controler", protection_status::BLOCK_IN_FREEMODE}}, + {224, {"am_darts_apartment", protection_status::BLOCK_ALWAYS}}, + {226, {"grid_arcade_cabinet", protection_status::BLOCK_ALWAYS}}, + {227, {"scroll_arcade_cabinet", protection_status::BLOCK_ALWAYS}}, + {228, {"example_arcade", protection_status::BLOCK_ALWAYS}}, + {229, {"road_arcade", protection_status::BLOCK_ALWAYS}}, + {230, {"gunslinger_arcade", protection_status::BLOCK_ALWAYS}}, // Badlands Revenge II? + {231, {"wizard_arcade", protection_status::BLOCK_ALWAYS}}, + {235, {"ggsm_arcade", protection_status::BLOCK_ALWAYS}}, // Space Monkey? + {236, {"puzzle", protection_status::BLOCK_ALWAYS}}, // Qub3d? + {237, {"camhedz_arcade", protection_status::BLOCK_ALWAYS}}, + {238, {"SCTV", protection_status::BLOCK_ALWAYS}}}; + } + }; +}