Merge branch 'master' into fix-cache-openfile-fail
This commit is contained in:
commit
4c36c15321
@ -3,7 +3,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
gtav_classes
|
||||
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
|
||||
GIT_TAG 09a586011a296cf8ce3ffb9c15db7ce474ea4363
|
||||
GIT_TAG ddd118410c5ede28e3a5978ebda93b83634d3293
|
||||
GIT_PROGRESS TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Table containing helper functions related to gta scripts.
|
||||
|
||||
## Functions (2)
|
||||
## Functions (3)
|
||||
|
||||
### `register_looped(name, func)`
|
||||
|
||||
@ -75,4 +75,15 @@ end)
|
||||
script.run_in_fiber(func)
|
||||
```
|
||||
|
||||
### `execute_as_script(script_name, func)`
|
||||
|
||||
- **Parameters:**
|
||||
- `script_name` (string): target script thread.
|
||||
- `func` (function): function that will be executed once in the script thread.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
script.execute_as_script(script_name, func)
|
||||
```
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace big
|
||||
return;
|
||||
if (!scripts::force_host("freemode"_J))
|
||||
{
|
||||
g_notification_service->push_error("END_KICK"_T.data(), "BACKEND_END_SESSION_KICK_FORCE_SCRIPT_HOST_FAILED"_T.data());
|
||||
g_notification_service.push_error("END_KICK"_T.data(), "BACKEND_END_SESSION_KICK_FORCE_SCRIPT_HOST_FAILED"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace big
|
||||
return;
|
||||
if (!g_player_service->get_self()->is_host())
|
||||
{
|
||||
g_notification_service->push_error("HOST_KICK"_T.data(), "BACKEND_HOST_KICK_FAILED"_T.data());
|
||||
g_notification_service.push_error("HOST_KICK"_T.data(), "BACKEND_HOST_KICK_FAILED"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -27,4 +27,4 @@ namespace big
|
||||
};
|
||||
|
||||
host_kick g_host_kick("hostkick", "HOST_KICK", "HOST_KICK_DESC", 0, false);
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace big
|
||||
return;
|
||||
if (!scripts::force_host("freemode"_J))
|
||||
{
|
||||
g_notification_service->push_error("Kick", "Force script host failed!");
|
||||
g_notification_service.push_error("Kick", "Force script host failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,11 @@ namespace big
|
||||
{
|
||||
if (!NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(id, "am_launcher", -1))
|
||||
{
|
||||
g_notification_service->push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_CANNOT_START_AM_LAUNCHER"_T.data());
|
||||
g_notification_service.push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_CANNOT_START_AM_LAUNCHER"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
g_notification_service->push("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_STARTING"_T.data());
|
||||
g_notification_service.push("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_STARTING"_T.data());
|
||||
|
||||
scripts::start_launcher_script(47);
|
||||
|
||||
@ -35,7 +35,7 @@ namespace big
|
||||
{
|
||||
if (i >= 1000)
|
||||
{
|
||||
g_notification_service->push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED"_T.data());
|
||||
g_notification_service.push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ namespace big
|
||||
|
||||
if (!scripts::force_host("am_hunt_the_beast"_J))
|
||||
{
|
||||
g_notification_service->push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED_CONTROL"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ namespace big
|
||||
{
|
||||
if (i >= 7000)
|
||||
{
|
||||
g_notification_service->push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED"_T.data());
|
||||
g_notification_service.push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ namespace big
|
||||
|
||||
if (!scripts::force_host("am_hunt_the_beast"_J))
|
||||
{
|
||||
g_notification_service->push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_error("TURN_INTO_BEAST"_T.data(), "BACKEND_TURN_INTO_BEAST_FAILED_CONTROL"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -26,11 +26,11 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
boost_vehicle g_boost_vehicle("boostveh", "BACKEND_BOOST_VEHICLE", "BACKEND_BOOST_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -26,11 +26,11 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
close_doors g_close_doors("closedoors", "BACKEND_CLOSE_VEHICLE_DOORS", "BACKEND_CLOSE_VEHICLE_DOORS_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -34,4 +34,4 @@ namespace big
|
||||
};
|
||||
|
||||
downgrade_vehicle g_downgrade_vehicle("downgradeveh", "BACKEND_DOWNGRADE_VEHICLE", "BACKEND_DOWNGRADE_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(player_ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -41,4 +41,4 @@ namespace big
|
||||
};
|
||||
|
||||
flip_180 g_flip_180("flip180", "BACKEND_FLIP", "BACKEND_FLIP_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ent, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -30,4 +30,4 @@ namespace big
|
||||
};
|
||||
|
||||
flying_vehicle g_flying_vehicle("flyingveh", "BACKEND_FLYING_VEHICLE", "BACKEND_FLYING_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -25,11 +25,11 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
kill_engine g_kill_engine("killengine", "BACKEND_KILL_VEHICLE_ENGINE", "BACKEND_KILL_VEHICLE_ENGINE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -27,4 +27,4 @@ namespace big
|
||||
};
|
||||
|
||||
lock_vehicle g_lock_vehicle("lockveh", "BACKEND_LOCK_VEHICLE", "BACKEND_LOCK_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -29,11 +29,11 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
open_doors g_open_doors("opendoors", "BACKEND_OPEN_VEHICLE_DOORS", "BACKEND_OPEN_VEHICLE_DOORS_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ namespace big
|
||||
if (veh == 0)
|
||||
{
|
||||
if (g.player.spectating)
|
||||
g_notification_service->push_warning("REMOTE_CONTROL"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("REMOTE_CONTROL"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
else
|
||||
g_notification_service->push_warning("REMOTE_CONTROL"_T.data(), std::format("{} {}", "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T, "BACKEND_REMOTE_CONTROL_VEHICLE_SPECTATE"_T).c_str());
|
||||
g_notification_service.push_warning("REMOTE_CONTROL"_T.data(), std::format("{} {}", "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T, "BACKEND_REMOTE_CONTROL_VEHICLE_SPECTATE"_T).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -27,4 +27,4 @@ namespace big
|
||||
};
|
||||
|
||||
remote_control_vehicle g_remote_control_vehicle("rcplayer", "BACKEND_REMOTE_CONTROL_VEHICLE", "BACKEND_REMOTE_CONTROL_VEHICLE_DESC", 0, false);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -28,4 +28,4 @@ namespace big
|
||||
vehicle_special_ability<1> g_special_boost_vehicle("svehboost", "BACKEND_SPECIAL_ABILITY_BOOST", "BACKEND_SPECIAL_ABILITY_BOOST_DESC", 0);
|
||||
vehicle_special_ability<3> g_special_shunt_left("sshuntleft", "BACKEND_SPECIAL_ABILITY_LEFT", "BACKEND_SPECIAL_ABILITY_LEFT_DESC", 0);
|
||||
vehicle_special_ability<2> g_special_shunt_right("sshuntright", "BACKEND_SPECIAL_ABILITY_RIGHT", "BACKEND_SPECIAL_ABILITY_RIGHT_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -25,11 +25,11 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
stop_vehicle g_stop_vehicle("stopveh", "BACKEND_STOP_VEHICLE", "BACKEND_STOP_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace big
|
||||
Ped ped = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(player->id());
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("VEHICLE"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("VEHICLE"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -27,4 +27,4 @@ namespace big
|
||||
};
|
||||
|
||||
unlock_vehicle g_unlock_vehicle("unlockveh", "BACKEND_UNLOCK_DOORS", "BACKEND_UNLOCK_DOORS_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace big
|
||||
|
||||
if (!PED::IS_PED_IN_ANY_VEHICLE(ped, true))
|
||||
{
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "ERROR_PLAYER_IS_NOT_IN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -27,4 +27,4 @@ namespace big
|
||||
};
|
||||
|
||||
upgrade_vehicle g_upgrade_vehicle("upgradeveh", "MAX_VEHICLE", "BACKEND_UPGRADE_VEHICLE_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ namespace big
|
||||
{
|
||||
player_mgr->RemovePlayer(plyr->get_net_game_player());
|
||||
}
|
||||
g_notification_service->push("EMPTY_SESSION"_T.data(), "BACKEND_WIPE_SESSION_COMPLETE"_T.data());
|
||||
g_notification_service.push("EMPTY_SESSION"_T.data(), "BACKEND_WIPE_SESSION_COMPLETE"_T.data());
|
||||
}
|
||||
};
|
||||
empty_session g_empty_session("emptysession", "EMPTY_SESSION", "BACKEND_WIPE_SESSION_DESC", 0);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace big
|
||||
|
||||
if (veh == 0)
|
||||
{
|
||||
g_notification_service->push_error("GUI_TAB_SPAWN_VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
g_notification_service.push_error("GUI_TAB_SPAWN_VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "fiber_pool.hpp"
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/chat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -26,18 +26,7 @@ namespace big
|
||||
|
||||
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<hooks::send_chat_message>()(*g_pointers->m_gta.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);
|
||||
});
|
||||
chat::send_message(output, this->get_sender(), true, true);
|
||||
}
|
||||
|
||||
void chat_command_context::report_error(const std::string& error) const
|
||||
|
@ -14,11 +14,11 @@ namespace big
|
||||
|
||||
void default_command_context::report_output(const std::string& output) const
|
||||
{
|
||||
g_notification_service->push("BACKEND_COMMAND"_T.data(), output);
|
||||
g_notification_service.push("BACKEND_COMMAND"_T.data(), output);
|
||||
}
|
||||
|
||||
void default_command_context::report_error(const std::string& error) const
|
||||
{
|
||||
g_notification_service->push_error("BACKEND_COMMAND"_T.data(), error);
|
||||
g_notification_service.push_error("BACKEND_COMMAND"_T.data(), error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
#include "file_manager.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "logger/logger.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/outfit/outfit_service.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
#include "services/tunables/tunables_service.hpp"
|
||||
|
||||
namespace big
|
||||
@ -15,13 +15,13 @@ namespace big
|
||||
int offset = 0;
|
||||
switch (model)
|
||||
{
|
||||
case "mp_m_freemode_01"_J: break;
|
||||
case "mp_f_freemode_01"_J:
|
||||
{
|
||||
offset = 1;
|
||||
break;
|
||||
}
|
||||
default: return false; //For non-normal models
|
||||
case "mp_m_freemode_01"_J: break;
|
||||
case "mp_f_freemode_01"_J:
|
||||
{
|
||||
offset = 1;
|
||||
break;
|
||||
}
|
||||
default: return false; //For non-normal models
|
||||
}
|
||||
|
||||
return PED::GET_PED_DRAWABLE_VARIATION(self::ped, ComponentId::AUXILIARY) == 15 && PED::GET_PED_DRAWABLE_VARIATION(self::ped, ComponentId::TORSO) == 15 && PED::GET_PED_DRAWABLE_VARIATION(self::ped, ComponentId::LEGS) == (14 + offset);
|
||||
@ -52,11 +52,28 @@ namespace big
|
||||
|
||||
if (persisting_outfit != g.self.persist_outfit)
|
||||
{
|
||||
persisting_outfit = g.self.persist_outfit;
|
||||
folder saved_outfit_path = g_file_manager.get_project_folder("saved_outfits");
|
||||
std::ifstream i(saved_outfit_path.get_file(persisting_outfit).get_path());
|
||||
outfit.clear();
|
||||
i >> outfit;
|
||||
persisting_outfit = g.self.persist_outfit;
|
||||
folder saved_outfit_path = g_file_manager.get_project_folder("saved_outfits");
|
||||
const auto persist_outfit_file_path = saved_outfit_path.get_file(persisting_outfit).get_path();
|
||||
if (std::filesystem::exists(persist_outfit_file_path))
|
||||
{
|
||||
std::ifstream i(persist_outfit_file_path);
|
||||
if (i.is_open())
|
||||
{
|
||||
outfit.clear();
|
||||
try
|
||||
{
|
||||
i >> outfit;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG(INFO) << e.what();
|
||||
|
||||
outfit = {};
|
||||
g.self.persist_outfit = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outfit.contains("model") && outfit["model"].get<uint32_t>() == model)
|
||||
|
@ -391,7 +391,7 @@ namespace big
|
||||
|
||||
virtual void on_enable() override
|
||||
{
|
||||
g_notification_service->push("SUPER_HERO_FLY"_T.data(), "SUPER_HERO_FLY_ENABLE_NOTIFICATION"_T.data());
|
||||
g_notification_service.push("SUPER_HERO_FLY"_T.data(), "SUPER_HERO_FLY_ENABLE_NOTIFICATION"_T.data());
|
||||
}
|
||||
|
||||
virtual void on_disable() override
|
||||
|
@ -19,7 +19,7 @@ namespace big
|
||||
{
|
||||
on_disable();
|
||||
g.self.passive = false;
|
||||
g_notification_service->push_warning("PASSIVE"_T.data(), "BACKEND_LOOPED_SELF_TOGGLE_PASSIVE_DISABLED_PASSIVE_MODE_MESSAGE"_T.data());
|
||||
g_notification_service.push_warning("PASSIVE"_T.data(), "BACKEND_LOOPED_SELF_TOGGLE_PASSIVE_DISABLED_PASSIVE_MODE_MESSAGE"_T.data());
|
||||
return;
|
||||
}
|
||||
*g_tunables_service->get_tunable<int*>(-29732167) = 0; // End Passive Time = 0s
|
||||
|
@ -29,7 +29,7 @@ namespace big
|
||||
{
|
||||
current_destination = AutoDriveDestination::STOPPED;
|
||||
changing_driving_styles = false;
|
||||
g_notification_service->push_warning("AUTO_DRIVE"_T.data(), "PLAYER_INFO_NO_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("AUTO_DRIVE"_T.data(), "PLAYER_INFO_NO_VEHICLE"_T.data());
|
||||
}
|
||||
else if (current_driving_flag != driving_style_flags[g.vehicle.auto_drive_style] || current_speed != g.vehicle.auto_drive_speed)
|
||||
{
|
||||
@ -77,11 +77,11 @@ namespace big
|
||||
|
||||
if (to_waypoint && !does_waypoint_exist)
|
||||
{
|
||||
g_notification_service->push_warning("AUTO_DRIVE"_T.data(), "TELEPORT_NO_WAYPOINT_SET"_T.data());
|
||||
g_notification_service.push_warning("AUTO_DRIVE"_T.data(), "TELEPORT_NO_WAYPOINT_SET"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("AUTO_DRIVE"_T.data(), "BACKEND_LOOPED_VEHICLE_AUTO_DRIVE_STOPPED"_T.data());
|
||||
g_notification_service.push_warning("AUTO_DRIVE"_T.data(), "BACKEND_LOOPED_VEHICLE_AUTO_DRIVE_STOPPED"_T.data());
|
||||
}
|
||||
|
||||
started = false;
|
||||
|
@ -125,7 +125,7 @@ namespace big
|
||||
|
||||
virtual void on_enable() override
|
||||
{
|
||||
g_notification_service->push("TURN_SIGNALS"_T.data(), "BACKEND_LOOPED_VEHICLE_TURN_SIGNALS_HELP"_T.data());
|
||||
g_notification_service.push("TURN_SIGNALS"_T.data(), "BACKEND_LOOPED_VEHICLE_TURN_SIGNALS_HELP"_T.data());
|
||||
}
|
||||
|
||||
virtual void on_tick() override
|
||||
|
@ -24,7 +24,7 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
g_notification_service.push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace big
|
||||
{
|
||||
if (ENTITY::IS_ENTITY_A_PED(entity) && PED::IS_PED_A_PLAYER(entity))
|
||||
{
|
||||
g_notification_service->push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_PLAYER"_T.data());
|
||||
g_notification_service.push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_PLAYER"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -29,7 +29,7 @@ namespace big
|
||||
|
||||
if (dist > 500)
|
||||
{
|
||||
g_notification_service->push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_TOO_FAR"_T.data());
|
||||
g_notification_service.push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_TOO_FAR"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -38,13 +38,13 @@ namespace big
|
||||
entity::delete_entity(entity);
|
||||
}
|
||||
else
|
||||
g_notification_service->push_error("CUSTOM_WEAPONS"_T.data(), "TELEPORT_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_error("CUSTOM_WEAPONS"_T.data(), "TELEPORT_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
g_notification_service.push_error("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace big
|
||||
{
|
||||
if (ENTITY::IS_ENTITY_A_PED(ent_to_add) && PED::IS_PED_A_PLAYER(ent_to_add))
|
||||
{
|
||||
g_notification_service->push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_PLAYER"_T.data());
|
||||
g_notification_service.push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_PLAYER"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -79,7 +79,7 @@ namespace big
|
||||
|
||||
if (temp_dist > 500)
|
||||
{
|
||||
g_notification_service->push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_TOO_FAR"_T.data());
|
||||
g_notification_service.push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_DELETE_GUN_TOO_FAR"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -87,7 +87,7 @@ namespace big
|
||||
{
|
||||
TASK::SET_HIGH_FALL_TASK(ent_to_add, 0, 0, 0);
|
||||
|
||||
g_notification_service->push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_SET"_T.data());
|
||||
g_notification_service.push_warning("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_SET"_T.data());
|
||||
}
|
||||
|
||||
ents.push_back(ent_to_add);
|
||||
@ -121,7 +121,7 @@ namespace big
|
||||
|
||||
ents.clear();
|
||||
|
||||
g_notification_service->push_success("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_UNSET"_T.data());
|
||||
g_notification_service.push_success("CUSTOM_WEAPONS"_T.data(), "BACKEND_LOOPED_WEAPONS_GRAVITY_GUN_UNSET"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,15 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("BACKEND_LOOPED_WEAPONS_REPAIR_GUN"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
g_notification_service.push_warning("BACKEND_LOOPED_WEAPONS_REPAIR_GUN"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("BACKEND_LOOPED_WEAPONS_REPAIR_GUN"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
g_notification_service.push_warning("BACKEND_LOOPED_WEAPONS_REPAIR_GUN"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ namespace big
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("BACKEND_LOOPED_WEAPONS_STEAL_VEHICLE_GUN"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
g_notification_service.push_warning("BACKEND_LOOPED_WEAPONS_STEAL_VEHICLE_GUN"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("BACKEND_LOOPED_WEAPONS_STEAL_VEHICLE_GUN"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
g_notification_service.push_warning("BACKEND_LOOPED_WEAPONS_STEAL_VEHICLE_GUN"_T.data(), "BACKEND_LOOPED_WEAPONS_CAGE_GUN_NO_ENTITY_FOUND"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace big
|
||||
|
||||
virtual void on_enable() override
|
||||
{
|
||||
g_notification_service->push("Auto disarm", "Nearby hostile peds will be disarmed");
|
||||
g_notification_service.push("Auto disarm", "Nearby hostile peds will be disarmed");
|
||||
}
|
||||
|
||||
virtual void on_tick() override
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/chat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -36,23 +36,16 @@ namespace big
|
||||
|
||||
if (announce_in_chat)
|
||||
{
|
||||
g_fiber_pool->queue_job([attacker, victim, this] {
|
||||
auto chat = std::format("{} {}", g.session.chat_output_prefix, g_translation_service.get_translation(m_announce_message));
|
||||
|
||||
if (g_hooking->get_original<hooks::send_chat_message>()(*g_pointers->m_gta.m_send_chat_ptr,
|
||||
g_player_service->get_self()->get_net_data(),
|
||||
chat.data(),
|
||||
is_team_only))
|
||||
notify::draw_chat(chat.c_str(), g_player_service->get_self()->get_name(), is_team_only);
|
||||
});
|
||||
auto msg = std::format("{} {}", g.session.chat_output_prefix, g_translation_service.get_translation(m_announce_message));
|
||||
chat::send_message(msg);
|
||||
}
|
||||
|
||||
if (notify)
|
||||
{
|
||||
g_notification_service->push_warning("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(),
|
||||
std::vformat(g_translation_service.get_translation(m_notify_message), std::make_format_args(attacker->get_name(), victim->get_name())));
|
||||
}
|
||||
|
||||
process_common(attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/chat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -62,20 +62,16 @@ namespace big
|
||||
|
||||
if (announce_in_chat)
|
||||
{
|
||||
g_fiber_pool->queue_job([player, this] {
|
||||
auto chat = std::format("{} {}", g.session.chat_output_prefix, std::vformat(g_translation_service.get_translation(m_announce_message), std::make_format_args(player->get_name())));
|
||||
auto msg = std::format("{} {}",
|
||||
g.session.chat_output_prefix,
|
||||
std::vformat(g_translation_service.get_translation(m_announce_message), std::make_format_args(player->get_name())));
|
||||
|
||||
if (g_hooking->get_original<hooks::send_chat_message>()(*g_pointers->m_gta.m_send_chat_ptr,
|
||||
g_player_service->get_self()->get_net_data(),
|
||||
chat.data(),
|
||||
is_team_only))
|
||||
notify::draw_chat(chat.c_str(), g_player_service->get_self()->get_name(), is_team_only);
|
||||
});
|
||||
chat::send_message(msg);
|
||||
}
|
||||
|
||||
if (notify)
|
||||
{
|
||||
g_notification_service->push_warning("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(),
|
||||
std::vformat(g_translation_service.get_translation(m_notify_message), std::make_format_args(player->get_name())));
|
||||
}
|
||||
|
||||
|
@ -293,8 +293,7 @@ namespace big
|
||||
GOD = 1 << 8,
|
||||
EXPLOSION = 1 << 11,
|
||||
STEAM = 1 << 15,
|
||||
DROWN = 1 << 16,
|
||||
WATER = 1 << 24,
|
||||
WATER = 1 << 16,
|
||||
};
|
||||
enum ePedType : uint32_t
|
||||
{
|
||||
|
@ -336,7 +336,6 @@ namespace big
|
||||
bool proof_melee = false;
|
||||
bool proof_explosion = false;
|
||||
bool proof_steam = false;
|
||||
bool proof_drown = false;
|
||||
bool proof_water = false;
|
||||
uint32_t proof_mask = 0;
|
||||
bool mobile_radio = false;
|
||||
@ -388,7 +387,7 @@ namespace big
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(super_hero_fly, gradual, explosions, auto_land, charge, ptfx, fly_speed, initial_launch)
|
||||
} super_hero_fly{};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ipls, ptfx_effects, clean_player, force_wanted_level, passive, free_cam, invisibility, local_visibility, never_wanted, no_ragdoll, noclip, noclip_aim_speed_multiplier, noclip_speed_multiplier, off_radar, super_run, no_collision, unlimited_oxygen, no_water_collision, wanted_level, god_mode, part_water, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_drown, proof_water, proof_mask, mobile_radio, fast_respawn, auto_tp, super_jump, beast_jump, healthregen, healthregenrate, hud, superman, custom_weapon_stop, prompt_ambient_animations, persist_outfit, persist_outfits_mis, interaction_menu_freedom, super_hero_fly)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ipls, ptfx_effects, clean_player, force_wanted_level, passive, free_cam, invisibility, local_visibility, never_wanted, no_ragdoll, noclip, noclip_aim_speed_multiplier, noclip_speed_multiplier, off_radar, super_run, no_collision, unlimited_oxygen, no_water_collision, wanted_level, god_mode, part_water, proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_water, proof_mask, mobile_radio, fast_respawn, auto_tp, super_jump, beast_jump, healthregen, healthregenrate, hud, superman, custom_weapon_stop, prompt_ambient_animations, persist_outfit, persist_outfits_mis, interaction_menu_freedom, super_hero_fly)
|
||||
} self{};
|
||||
|
||||
struct session
|
||||
|
@ -210,4 +210,6 @@ namespace big::functions
|
||||
using get_ped_seat = CGetPedSeatReturnClass*(*)(PVOID seat_info, CPed* ped);
|
||||
|
||||
using received_clone_remove = void (*)(CNetworkObjectMgr*, CNetGamePlayer*, CNetGamePlayer*, int16_t, uint32_t);
|
||||
|
||||
using can_create_vehicle = bool (*)();
|
||||
}
|
||||
|
@ -91,9 +91,9 @@ namespace rage
|
||||
{
|
||||
return big::g_pointers->m_gta.m_read_bitbuf_bool(this, boolean, 1);
|
||||
}
|
||||
bool ReadPeerId(uint64_t* peer_id)
|
||||
bool ReadRockstarId(int64_t* rockstar_id)
|
||||
{
|
||||
return this->ReadQWord(peer_id, 0x40);
|
||||
return this->ReadInt64(rockstar_id, sizeof(rockstar_id) * 8);
|
||||
}
|
||||
uint64_t ReadBits(size_t numBits)
|
||||
{
|
||||
@ -207,6 +207,10 @@ namespace rage
|
||||
{
|
||||
return big::g_pointers->m_gta.m_write_bitbuf_int64(this, integer, bits);
|
||||
}
|
||||
bool WriteRockstarId(int64_t rockstar_id)
|
||||
{
|
||||
return big::g_pointers->m_gta.m_write_bitbuf_int64(this, rockstar_id, sizeof(rockstar_id) * 8);
|
||||
}
|
||||
bool ReadInt64(int64_t* integer, int bits)
|
||||
{
|
||||
uint32_t v8;
|
||||
|
@ -365,6 +365,8 @@ namespace big
|
||||
functions::received_clone_remove m_received_clone_remove;
|
||||
|
||||
CWeaponInfoManager* m_weapon_info_manager;
|
||||
|
||||
functions::can_create_vehicle m_can_create_vehicle;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned");
|
||||
|
@ -140,6 +140,8 @@ namespace big
|
||||
|
||||
detour_hook_helper::add<hooks::received_clone_remove>("RCR", g_pointers->m_gta.m_received_clone_remove);
|
||||
|
||||
detour_hook_helper::add<hooks::can_create_vehicle>("CCV", g_pointers->m_gta.m_can_create_vehicle);
|
||||
|
||||
g_hooking = this;
|
||||
}
|
||||
|
||||
|
@ -191,6 +191,8 @@ namespace big
|
||||
static bool sync_reader_serialize_vec3(void* _this, rage::fvector3* vec, float divisor, int size);
|
||||
static bool sync_reader_serialize_vec3_signed(void* _this, rage::fvector3* vec, float divisor, int size);
|
||||
static bool sync_reader_serialize_array(void* _this, void* array, int size);
|
||||
|
||||
static bool can_create_vehicle();
|
||||
};
|
||||
|
||||
class minhook_keepalive
|
||||
|
@ -64,11 +64,11 @@ namespace big
|
||||
g_fiber_pool->queue_job([] {
|
||||
session::join_session(gta_util::get_network()->m_last_joined_session.m_session_info);
|
||||
});
|
||||
g_notification_service->push_warning("KICKED"_T.data(), "You have been desync kicked. Rejoining previous session...");
|
||||
g_notification_service.push_warning("KICKED"_T.data(), "You have been desync kicked. Rejoining previous session...");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("KICKED"_T.data(), "USER_DESYNC_KICKED"_T.data());
|
||||
g_notification_service.push_warning("KICKED"_T.data(), "USER_DESYNC_KICKED"_T.data());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -5,36 +5,19 @@
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "packet.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/spam.hpp"
|
||||
#include "util/chat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
inline void gamer_handle_serialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
||||
{
|
||||
constexpr int PC_PLATFORM = 3;
|
||||
buf.Write<uint8_t>(PC_PLATFORM, 8);
|
||||
buf.WriteInt64(*(int64_t*)&hnd.m_rockstar_id, 64);
|
||||
buf.Write<uint8_t>(hnd.unk_0009, 8);
|
||||
}
|
||||
|
||||
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<chat_command_context>(g_player_service->get_self()));
|
||||
|
||||
packet msg{};
|
||||
msg.write_message(rage::eNetMessage::MsgTextMessage);
|
||||
msg.m_buffer.WriteString(message ? message : "", 256);
|
||||
gamer_handle_serialize(g_player_service->get_self()->get_net_data()->m_gamer_handle, msg.m_buffer);
|
||||
msg.write<bool>(is_team, 1);
|
||||
chat::send_message(message, nullptr, false, is_team);
|
||||
|
||||
if (g.session.log_chat_messages)
|
||||
spam::log_chat(message, g_player_service->get_self(), SpamReason::NOT_A_SPAMMER, is_team);
|
||||
|
||||
if (*g_pointers->m_gta.m_is_session_started)
|
||||
for (auto& player : g_player_service->players())
|
||||
if (player.second && player.second->is_valid())
|
||||
msg.send(player.second->get_net_game_player()->m_msg_id);
|
||||
chat::log_chat(message, g_player_service->get_self(), SpamReason::NOT_A_SPAMMER, is_team);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace big
|
||||
|
||||
if (g.notifications.player_leave.notify)
|
||||
{
|
||||
g_notification_service->push("PLAYER_LEFT"_T.data(),
|
||||
g_notification_service.push("PLAYER_LEFT"_T.data(),
|
||||
std::vformat("PLAYER_LEFT_INFO"_T,
|
||||
std::make_format_args(net_player_data->m_name,
|
||||
player->m_player_id,
|
||||
@ -60,7 +60,7 @@ namespace big
|
||||
{
|
||||
if (admin_rids.contains(net_player_data->m_gamer_handle.m_rockstar_id))
|
||||
{
|
||||
g_notification_service->push_warning("POTENTIAL_ADMIN_FOUND"_T.data(),
|
||||
g_notification_service.push_warning("POTENTIAL_ADMIN_FOUND"_T.data(),
|
||||
std::format("{} {}", net_player_data->m_name, "PLAYER_DETECTED_AS_ADMIN"_T));
|
||||
|
||||
LOG(WARNING) << net_player_data->m_name << " (" << net_player_data->m_gamer_handle.m_rockstar_id << ") has been detected as an admin";
|
||||
@ -82,7 +82,7 @@ namespace big
|
||||
|
||||
if (g.notifications.player_join.notify)
|
||||
{
|
||||
g_notification_service->push("PLAYER_JOINED"_T.data(),
|
||||
g_notification_service.push("PLAYER_JOINED"_T.data(),
|
||||
std::vformat("PLAYER_JOINED_INFO"_T,
|
||||
std::make_format_args(net_player_data->m_name,
|
||||
player->m_player_id,
|
||||
@ -109,7 +109,7 @@ namespace big
|
||||
|
||||
if (strcmp(plyr->get_name(), entry->name.data()))
|
||||
{
|
||||
g_notification_service->push("PLAYERS"_T.data(),
|
||||
g_notification_service.push("PLAYERS"_T.data(),
|
||||
std::format("{} {}: {}", entry->name, "PLAYER_CHANGED_NAME"_T, plyr->get_name()));
|
||||
entry->name = plyr->get_name();
|
||||
g_player_database_service->save();
|
||||
@ -133,14 +133,14 @@ namespace big
|
||||
{
|
||||
if ((plyr->is_friend() && g.session.allow_friends_into_locked_session) || plyr->is_trusted)
|
||||
{
|
||||
g_notification_service->push_success("LOBBY_LOCK"_T.data(),
|
||||
g_notification_service.push_success("LOBBY_LOCK"_T.data(),
|
||||
std::vformat("LOBBY_LOCK_ALLOWED"_T.data(),
|
||||
std::make_format_args(plyr->get_net_data()->m_name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic_cast<player_command*>(command::get("multikick"_J))->call(plyr, {});
|
||||
g_notification_service->push_warning("LOBBY_LOCK"_T.data(),
|
||||
g_notification_service.push_warning("LOBBY_LOCK"_T.data(),
|
||||
std::vformat("LOBBY_LOCK_DENIED"_T.data(), std::make_format_args(plyr->get_net_data()->m_name)));
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
if (g.notifications.network_player_mgr_init.log)
|
||||
LOG(INFO) << "CNetworkPlayerMgr#init got called, we're probably entering a session.";
|
||||
if (g.notifications.network_player_mgr_init.notify)
|
||||
g_notification_service->push("NETWORK_PLAYER_MGR"_T.data(), "NETWORK_PLAYER_MGR_INIT"_T.data());
|
||||
g_notification_service.push("NETWORK_PLAYER_MGR"_T.data(), "NETWORK_PLAYER_MGR_INIT"_T.data());
|
||||
|
||||
bool result = g_hooking->get_original<hooks::network_player_mgr_init>()(_this, a2, a3, a4);
|
||||
|
||||
@ -32,7 +32,7 @@ namespace big
|
||||
if (g.notifications.network_player_mgr_shutdown.log)
|
||||
LOG(INFO) << "CNetworkPlayerMgr#shutdown got called, we're probably leaving our session.";
|
||||
if (g.notifications.network_player_mgr_shutdown.notify)
|
||||
g_notification_service->push("NETWORK_PLAYER_MGR"_T.data(), "NETWORK_PLAYER_MGR_DESTROY"_T.data());
|
||||
g_notification_service.push("NETWORK_PLAYER_MGR"_T.data(), "NETWORK_PLAYER_MGR_DESTROY"_T.data());
|
||||
|
||||
g.session.trust_session = false;
|
||||
g_hooking->get_original<hooks::network_player_mgr_shutdown>()(_this);
|
||||
|
@ -73,8 +73,8 @@ namespace big
|
||||
if (memory)
|
||||
return memory;
|
||||
|
||||
g_notification_service->push_error("Protections", "The network message allocator is out of memory"); // this never reaches here but why not
|
||||
g_notification_service.push_error("Protections", "The network message allocator is out of memory"); // this never reaches here but why not
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,13 +716,9 @@ namespace big
|
||||
case sync_node_id("CPlayerExtendedGameStateNode"):
|
||||
LOG_FIELD(CPlayerExtendedGameStateNode, waypoint_x);
|
||||
LOG_FIELD(CPlayerExtendedGameStateNode, waypoint_y);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, unk1);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, unk2);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, unk3);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, unk4);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, unk5);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, has_waypoint_data);
|
||||
LOG_FIELD_B(CPlayerExtendedGameStateNode, is_waypoint_set);
|
||||
LOG_FIELD(CPlayerExtendedGameStateNode, waypoint_entity);
|
||||
LOG_FIELD(CPlayerExtendedGameStateNode, has_active_waypoint);
|
||||
LOG_FIELD(CPlayerExtendedGameStateNode, owns_waypoint);
|
||||
break;
|
||||
case sync_node_id("CPlayerGameStateDataNode"):
|
||||
LOG_FIELD(CPlayerGameStateDataNode, m_player_state);
|
||||
|
@ -16,7 +16,7 @@ namespace big
|
||||
CMsgJoinResponse response{};
|
||||
response.m_status_code = player->block_join_reason;
|
||||
g_pointers->m_gta.m_write_join_response_data(&response, ctx->m_join_response_data, 512, &ctx->m_join_response_size);
|
||||
g_notification_service->push("BLOCK_JOIN"_T.data(),
|
||||
g_notification_service.push("BLOCK_JOIN"_T.data(),
|
||||
std::vformat("BLOCK_JOIN_INFO"_T, std::make_format_args(player->name)));
|
||||
return false;
|
||||
}
|
||||
@ -25,4 +25,4 @@ namespace big
|
||||
return g_hooking->get_original<hooks::handle_join_request>()(network, session, player_info, ctx, is_transition_session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "script/scriptIdBase.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "util/spam.hpp"
|
||||
#include "util/chat.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
|
||||
#include <network/Network.hpp>
|
||||
@ -19,12 +19,11 @@
|
||||
|
||||
inline void gamer_handle_deserialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
||||
{
|
||||
constexpr int PC_PLATFORM = 3;
|
||||
if ((hnd.m_platform = buf.Read<uint8_t>(8)) != PC_PLATFORM)
|
||||
if ((hnd.m_platform = buf.Read<uint8_t>(sizeof(hnd.m_platform) * 8)) != rage::rlPlatforms::PC)
|
||||
return;
|
||||
|
||||
buf.ReadInt64((int64_t*)&hnd.m_rockstar_id, 64);
|
||||
hnd.unk_0009 = buf.Read<uint8_t>(8);
|
||||
buf.ReadRockstarId(&hnd.m_rockstar_id);
|
||||
hnd.m_padding = buf.Read<uint8_t>(sizeof(hnd.m_padding) * 8);
|
||||
}
|
||||
|
||||
inline bool is_kick_instruction(rage::datBitBuffer& buffer)
|
||||
@ -107,18 +106,21 @@ namespace big
|
||||
case rage::eNetMessage::MsgTextMessage2:
|
||||
{
|
||||
char message[256];
|
||||
buffer.ReadString(message, 256);
|
||||
rage::rlGamerHandle handle{};
|
||||
bool is_team;
|
||||
buffer.ReadString(message, sizeof(message));
|
||||
gamer_handle_deserialize(handle, buffer);
|
||||
buffer.ReadBool(&is_team);
|
||||
|
||||
if (player->is_spammer)
|
||||
return true;
|
||||
|
||||
if (auto spam_reason = spam::is_text_spam(message, player))
|
||||
if (auto spam_reason = chat::is_text_spam(message, player))
|
||||
{
|
||||
if (g.session.log_chat_messages)
|
||||
spam::log_chat(message, player, spam_reason, is_team);
|
||||
g_notification_service->push("PROTECTIONS"_T.data(),
|
||||
chat::log_chat(message, player, spam_reason, is_team);
|
||||
g_notification_service.push("PROTECTIONS"_T.data(),
|
||||
|
||||
std::format("{} {}", player->get_name(), "IS_A_SPAMMER"_T.data()));
|
||||
player->is_spammer = true;
|
||||
if (g.session.kick_chat_spammers
|
||||
@ -136,7 +138,7 @@ namespace big
|
||||
else
|
||||
{
|
||||
if (g.session.log_chat_messages)
|
||||
spam::log_chat(message, player, SpamReason::NOT_A_SPAMMER, is_team);
|
||||
chat::log_chat(message, player, SpamReason::NOT_A_SPAMMER, is_team);
|
||||
|
||||
if (g.session.chat_commands && message[0] == g.session.chat_command_prefix)
|
||||
command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
|
||||
@ -145,16 +147,8 @@ namespace big
|
||||
|
||||
if (msgType == rage::eNetMessage::MsgTextMessage && g_pointers->m_gta.m_chat_data && player->get_net_data())
|
||||
{
|
||||
rage::rlGamerHandle temp{};
|
||||
gamer_handle_deserialize(temp, buffer);
|
||||
bool is_team = buffer.Read<bool>(1);
|
||||
|
||||
g_pointers->m_gta.m_handle_chat_message(*g_pointers->m_gta.m_chat_data,
|
||||
nullptr,
|
||||
&player->get_net_data()->m_gamer_handle,
|
||||
message,
|
||||
is_team);
|
||||
return true;
|
||||
buffer.Seek(0);
|
||||
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame); // Call original function since we can't seem to handle it
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -166,7 +160,7 @@ namespace big
|
||||
if (player->m_host_migration_rate_limit.exceeded_last_process())
|
||||
{
|
||||
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
||||
g_notification_service->push_error("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_error("PROTECTIONS"_T.data(),
|
||||
std::vformat("OOM_KICK"_T, std::make_format_args(player->get_name())));
|
||||
}
|
||||
return true;
|
||||
@ -209,7 +203,7 @@ namespace big
|
||||
|
||||
if (reason == KickReason::VOTED_OUT)
|
||||
{
|
||||
g_notification_service->push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -225,7 +219,7 @@ namespace big
|
||||
if (player->m_radio_request_rate_limit.exceeded_last_process())
|
||||
{
|
||||
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
||||
g_notification_service->push_error("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_error("PROTECTIONS"_T.data(),
|
||||
std::vformat("OOM_KICK"_T, std::make_format_args(player->get_name())));
|
||||
player->block_radio_requests = true;
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ namespace big
|
||||
{
|
||||
if (g.protections.receive_pickup)
|
||||
{
|
||||
g_notification_service->push_error("PROTECTIONS"_T.data(), "Blocked pickup");
|
||||
g_notification_service.push_error("PROTECTIONS"_T.data(), "Blocked pickup");
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_hooking->get_original<hooks::receive_pickup>()(object, unk, ped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ namespace big
|
||||
&& player->m_player_info->m_ped && player->m_player_info->m_ped->m_net_object
|
||||
&& ownerNetId != player->m_player_info->m_ped->m_net_object->m_object_id && !offset_object)
|
||||
{
|
||||
g_notification_service->push_error("WARNING"_T.data(),
|
||||
g_notification_service.push_error("WARNING"_T.data(),
|
||||
std::vformat("BLAMED_FOR_EXPLOSION"_T,
|
||||
std::make_format_args(player->get_name(),
|
||||
reinterpret_cast<CPed*>(entity)->m_player_info->m_net_player_data.m_name)));
|
||||
@ -615,7 +615,7 @@ namespace big
|
||||
if (g_local_player && g_local_player->m_net_object && g_local_player->m_net_object->m_object_id == net_id)
|
||||
{
|
||||
weapon_item weapon = g_gta_data_service->weapon_by_hash(hash);
|
||||
g_notification_service->push_warning("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(),
|
||||
std::format("{} {} {}.", source_player->get_name(), "REMOVE_WEAPON_ATTEMPT_MESSAGE"_T, weapon.m_display_name));
|
||||
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
@ -632,7 +632,7 @@ namespace big
|
||||
if (g_local_player && g_local_player->m_net_object && g_local_player->m_net_object->m_object_id == net_id)
|
||||
{
|
||||
weapon_item weapon = g_gta_data_service->weapon_by_hash(hash);
|
||||
g_notification_service->push_warning("PROTECTIONS"_T.data(),
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(),
|
||||
std::format("{} {} {}.", source_player->get_name(), "GIVE_WEAPON_ATTEMPT_MESSAGE"_T, weapon.m_display_name));
|
||||
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
|
@ -20,7 +20,7 @@ namespace big
|
||||
LOG(WARNING) << "BLOCKED_SCRIPT_EVENT From: " << player_name << " Event Type: " << protection_type;
|
||||
|
||||
if (should_notify)
|
||||
g_notification_service->push_warning("Script Event Protection",
|
||||
g_notification_service.push_warning("Script Event Protection",
|
||||
std::format("From: {}\nEvent Type: {}", player_name.data(), protection_type.data()));
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace big
|
||||
if (plyr && plyr->block_join && *g_pointers->m_gta.m_is_session_started)
|
||||
{
|
||||
data->m_bubble_id = 10;
|
||||
g_notification_service->push("BLOCK_JOIN"_T.data(), std::vformat("BLOCK_JOIN_PREVENT_PLAYER_JOIN"_T, std::make_format_args(plyr->get_name())));
|
||||
g_notification_service.push("BLOCK_JOIN"_T.data(), std::vformat("BLOCK_JOIN_PREVENT_PLAYER_JOIN"_T, std::make_format_args(plyr->get_name())));
|
||||
}
|
||||
|
||||
bool result = g_hooking->get_original<hooks::send_non_physical_player_data>()(player, message, flags, a4, a5);
|
||||
@ -25,4 +25,4 @@ namespace big
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
src/hooks/script/can_create_vehicle.cpp
Normal file
10
src/hooks/script/can_create_vehicle.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "gta/pools.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::can_create_vehicle()
|
||||
{
|
||||
return (**g_pointers->m_gta.m_vehicle_pool)->m_item_count < (**g_pointers->m_gta.m_vehicle_pool)->m_size;
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ namespace big
|
||||
LOG(INFO) << "Script Thread '" << thread->m_name << "' terminated (" << thread->m_exit_message << ").";
|
||||
|
||||
if (g.notifications.gta_thread_kill.notify)
|
||||
g_notification_service->push("Script Thread Termination",
|
||||
g_notification_service.push("Script Thread Termination",
|
||||
std::format("Script Thread '{}' terminated.", thread->m_name));
|
||||
|
||||
if (thread == g.m_hunt_the_beast_thread)
|
||||
|
@ -12,7 +12,7 @@ namespace big
|
||||
if (g.notifications.gta_thread_kill.log)
|
||||
LOG(INFO) << "Script Thread '" << name << "' started.";
|
||||
if (g.notifications.gta_thread_kill.notify)
|
||||
g_notification_service->push("Script Thread Startup", std::format("Script Thread '{}' started.", name));
|
||||
g_notification_service.push("Script Thread Startup", std::format("Script Thread '{}' started.", name));
|
||||
}
|
||||
|
||||
return new_thread;
|
||||
|
@ -22,7 +22,6 @@ namespace big
|
||||
m_console_logger = &logger::format_console_simple;
|
||||
}
|
||||
|
||||
toggle_external_console(attach_console);
|
||||
create_backup();
|
||||
m_file_out.open(m_file.get_path(), std::ios_base::out | std::ios_base::trunc);
|
||||
|
||||
@ -33,6 +32,8 @@ namespace big
|
||||
Logger::AddSink([this](LogMessagePtr msg) {
|
||||
format_file(std::move(msg));
|
||||
});
|
||||
|
||||
toggle_external_console(attach_console);
|
||||
}
|
||||
|
||||
void logger::destroy()
|
||||
@ -44,6 +45,19 @@ namespace big
|
||||
|
||||
void logger::toggle_external_console(bool toggle)
|
||||
{
|
||||
if (m_is_console_open == toggle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_is_console_open = toggle;
|
||||
|
||||
m_console_out.close();
|
||||
if (m_did_console_exist)
|
||||
SetConsoleMode(m_console_handle, m_original_console_mode);
|
||||
|
||||
if (!m_did_console_exist)
|
||||
FreeConsole();
|
||||
|
||||
if (toggle)
|
||||
{
|
||||
if (m_did_console_exist = ::AttachConsole(GetCurrentProcessId()); !m_did_console_exist)
|
||||
@ -60,23 +74,12 @@ namespace big
|
||||
|
||||
// terminal like behaviour enable full color support
|
||||
console_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||
// prevent clicking in terminal from suspending our main thread
|
||||
console_mode &= ~(ENABLE_QUICK_EDIT_MODE);
|
||||
|
||||
SetConsoleMode(m_console_handle, console_mode);
|
||||
}
|
||||
|
||||
m_console_out.open("CONOUT$", std::ios_base::out | std::ios_base::app);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_console_out.close();
|
||||
if (m_did_console_exist)
|
||||
SetConsoleMode(m_console_handle, m_original_console_mode);
|
||||
|
||||
if (!m_did_console_exist)
|
||||
FreeConsole();
|
||||
}
|
||||
|
||||
void logger::create_backup()
|
||||
@ -119,6 +122,11 @@ namespace big
|
||||
|
||||
void logger::format_console(const LogMessagePtr msg)
|
||||
{
|
||||
if (!m_is_console_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto color = get_color(msg->Level());
|
||||
|
||||
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
|
||||
@ -133,6 +141,11 @@ namespace big
|
||||
|
||||
void logger::format_console_simple(const LogMessagePtr msg)
|
||||
{
|
||||
if (!m_is_console_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto color = get_color(msg->Level());
|
||||
|
||||
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
|
||||
|
@ -28,6 +28,7 @@ namespace big
|
||||
private:
|
||||
bool m_attach_console = true;
|
||||
bool m_did_console_exist = false;
|
||||
bool m_is_console_open = false;
|
||||
|
||||
void (logger::*m_console_logger)(const LogMessagePtr msg) = &logger::format_console;
|
||||
|
||||
@ -59,4 +60,4 @@ namespace big
|
||||
};
|
||||
|
||||
inline logger g_log{};
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ namespace lua::gui
|
||||
// Shows a message to the user with the given title and message.
|
||||
static void show_message(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push(title, message);
|
||||
big::g_notification_service.push(title, message);
|
||||
}
|
||||
|
||||
// Lua API: Function
|
||||
@ -262,7 +262,7 @@ namespace lua::gui
|
||||
// Shows a warning to the user with the given title and message.
|
||||
static void show_warning(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push_warning(title, message);
|
||||
big::g_notification_service.push_warning(title, message);
|
||||
}
|
||||
|
||||
// Lua API: Function
|
||||
@ -273,7 +273,7 @@ namespace lua::gui
|
||||
// Shows an error to the user with the given title and message.
|
||||
static void show_error(const std::string& title, const std::string& message)
|
||||
{
|
||||
big::g_notification_service->push_error(title, message);
|
||||
big::g_notification_service.push_error(title, message);
|
||||
}
|
||||
|
||||
// Lua API: Function
|
||||
@ -373,4 +373,4 @@ namespace lua::gui
|
||||
tab_ut["add_input_string"] = &tab::add_input_string;
|
||||
tab_ut["add_imgui"] = &tab::add_imgui;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "pointers.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/chat.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "util/system.hpp"
|
||||
@ -183,13 +184,22 @@ namespace lua::network
|
||||
// Sends a message to the in game chat.
|
||||
static void send_chat_message(const std::string& msg, bool team_only)
|
||||
{
|
||||
big::g_fiber_pool->queue_job([msg, team_only] {
|
||||
if (big::g_hooking->get_original<big::hooks::send_chat_message>()(*big::g_pointers->m_gta.m_send_chat_ptr,
|
||||
big::g_player_service->get_self()->get_net_data(),
|
||||
(char*)msg.c_str(),
|
||||
team_only))
|
||||
big::notify::draw_chat((char*)msg.data(), big::g_player_service->get_self()->get_name(), team_only);
|
||||
});
|
||||
big::chat::send_message(msg, nullptr, true, team_only);
|
||||
}
|
||||
|
||||
// Lua API: Function
|
||||
// Table: network
|
||||
// Name: send_chat_message_to_player
|
||||
// Param: player_idx: integer: Index of the player.
|
||||
// Param: msg: string: Message to be sent.
|
||||
// Sends a chat message to the specified player. Other players would not be able to see the message
|
||||
static void send_chat_message_to_player(int player_idx, const std::string& msg)
|
||||
{
|
||||
if (auto player = big::g_player_service->get_by_id(player_idx))
|
||||
{
|
||||
big::chat::send_message(msg, player);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void bind(sol::state& state)
|
||||
@ -229,5 +239,6 @@ namespace lua::network
|
||||
ns["get_flagged_modder_reason"] = get_flagged_modder_reason;
|
||||
ns["force_script_host"] = force_script_host;
|
||||
ns["send_chat_message"] = send_chat_message;
|
||||
ns["send_chat_message_to_player"] = send_chat_message_to_player;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "lua/lua_manager.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
#include "gta_util.hpp"
|
||||
|
||||
namespace lua::script
|
||||
{
|
||||
@ -151,15 +152,26 @@ namespace lua::script
|
||||
module->m_registered_scripts.push_back(std::move(lua_script));
|
||||
}
|
||||
|
||||
// Lua API: function
|
||||
// Table: script
|
||||
// Name: execute_as_script
|
||||
// Param: script_name: string: target script thread.
|
||||
// Param: func: function: function that will be executed once in the script thread.
|
||||
static void execute_as_script(const std::string& script_name, sol::protected_function func)
|
||||
{
|
||||
big::gta_util::execute_as_script(rage::joaat(script_name), func);
|
||||
}
|
||||
|
||||
void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["script"].get_or_create<sol::table>();
|
||||
ns["register_looped"] = register_looped;
|
||||
ns["run_in_fiber"] = run_in_fiber;
|
||||
ns["execute_as_script"] = execute_as_script;
|
||||
|
||||
auto usertype = state.new_usertype<script_util>("script_util");
|
||||
|
||||
usertype["yield"] = sol::yielding(&script_util::yield);
|
||||
usertype["sleep"] = sol::yielding(&script_util::sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,9 +152,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
g_file_manager.init(base_dir);
|
||||
|
||||
g.init(g_file_manager.get_project_file("./settings.json"));
|
||||
LOG(INFO) << "Settings Loaded.";
|
||||
|
||||
g_log.initialize("YimMenu", g_file_manager.get_project_file("./cout.log"), g.debug.external_console);
|
||||
LOG(INFO) << "Settings Loaded and logger initialized.";
|
||||
|
||||
LOG(INFO) << "Yim's Menu Initializing";
|
||||
LOGF(INFO, "Git Info\n\tBranch:\t{}\n\tHash:\t{}\n\tDate:\t{}", version::GIT_BRANCH, version::GIT_SHA1, version::GIT_DATE);
|
||||
@ -211,7 +210,6 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
auto context_menu_service_instance = std::make_unique<context_menu_service>();
|
||||
auto custom_text_service_instance = std::make_unique<custom_text_service>();
|
||||
auto mobile_service_instance = std::make_unique<mobile_service>();
|
||||
auto notification_service_instance = std::make_unique<notification_service>();
|
||||
auto pickup_service_instance = std::make_unique<pickup_service>();
|
||||
auto player_service_instance = std::make_unique<player_service>();
|
||||
auto gta_data_service_instance = std::make_unique<gta_data_service>();
|
||||
@ -229,6 +227,9 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
auto xml_maps_service_instance = std::make_unique<xml_map_service>();
|
||||
LOG(INFO) << "Registered service instances...";
|
||||
|
||||
g_notification_service.initialise();
|
||||
LOG(INFO) << "Finished initialising services.";
|
||||
|
||||
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func, "GUI", false));
|
||||
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::loop, "Backend Loop", false));
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
if (g.notifications.transaction_rate_limit.log)
|
||||
LOG(WARNING) << "Received transaction rate limit";
|
||||
if (g.notifications.transaction_rate_limit.notify)
|
||||
g_notification_service->push_warning("TRANSACTION_RATE_LIMIT"_T.data(), "TRANSACTION_RATE_LIMIT_MESSAGE"_T.data());
|
||||
g_notification_service.push_warning("TRANSACTION_RATE_LIMIT"_T.data(), "TRANSACTION_RATE_LIMIT_MESSAGE"_T.data());
|
||||
|
||||
*scr_globals::transaction_overlimit.as<PBOOL>() = FALSE;
|
||||
|
||||
@ -23,4 +23,4 @@ namespace big
|
||||
HUD::SET_WARNING_MESSAGE_WITH_HEADER(src->get_arg<const char*>(0), src->get_arg<const char*>(1), src->get_arg<int>(2), src->get_arg<const char*>(3), src->get_arg<BOOL>(4), src->get_arg<Any>(5), src->get_arg<Any*>(6), src->get_arg<Any*>(7), src->get_arg<BOOL>(8), src->get_arg<Any>(9));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1772,6 +1772,15 @@ namespace big
|
||||
{
|
||||
g_pointers->m_gta.m_weapon_info_manager = ptr.add(3).rip().sub(72).as<CWeaponInfoManager*>();
|
||||
}
|
||||
},
|
||||
// Can Create Vehicle
|
||||
{
|
||||
"CCV",
|
||||
"8B 0D ? ? ? ? 39 0D ? ? ? ? 0F 9C C0",
|
||||
[](memory::handle ptr)
|
||||
{
|
||||
g_pointers->m_gta.m_can_create_vehicle = ptr.as<functions::can_create_vehicle>();
|
||||
}
|
||||
}
|
||||
>(); // don't leave a trailing comma at the end
|
||||
|
||||
|
@ -71,7 +71,7 @@ namespace big
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(m_handle, false, true, false);
|
||||
}
|
||||
else
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"FIX VEHICLE",
|
||||
[this] {
|
||||
@ -83,7 +83,7 @@ namespace big
|
||||
VEHICLE::SET_VEHICLE_DIRT_LEVEL(m_handle, 0.f);
|
||||
}
|
||||
else
|
||||
g_notification_service->push_warning("WARNING"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("WARNING"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"BURST TIRES",
|
||||
[this] {
|
||||
@ -97,7 +97,7 @@ namespace big
|
||||
}
|
||||
}
|
||||
else
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"HALT",
|
||||
[this] {
|
||||
@ -106,7 +106,7 @@ namespace big
|
||||
VEHICLE::BRING_VEHICLE_TO_HALT(m_handle, 1, 5, true);
|
||||
}
|
||||
else
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"COPY VEHICLE",
|
||||
[this] {
|
||||
@ -119,14 +119,14 @@ namespace big
|
||||
if (entity::take_control_of(m_handle))
|
||||
VEHICLE::SET_VEHICLE_FORWARD_SPEED(m_handle, 79);
|
||||
else
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"LAUNCH",
|
||||
[this] {
|
||||
if (entity::take_control_of(m_handle))
|
||||
ENTITY::APPLY_FORCE_TO_ENTITY(m_handle, 1, 0.f, 0.f, 50000.f, 0.f, 0.f, 0.f, 0, 0, 1, 1, 0, 1);
|
||||
else
|
||||
g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
}},
|
||||
{"EJECT",
|
||||
[this] {
|
||||
@ -225,7 +225,7 @@ namespace big
|
||||
{
|
||||
{"COPY HASH", [this] {
|
||||
ImGui::SetClipboardText(std::format("0x{:08X}", (rage::joaat_t)m_pointer->m_model_info->m_hash).c_str());
|
||||
g_notification_service->push("Context Menu",
|
||||
g_notification_service.push("Context Menu",
|
||||
std::format("Copy hash 0x{:08X}", (rage::joaat_t)m_pointer->m_model_info->m_hash).c_str());
|
||||
}},
|
||||
{"EXPLODE",
|
||||
|
@ -46,7 +46,7 @@ namespace big
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
g_notification_service->push_error("CREATOR_STORAGE_SAVE_JOB"_T.data(),
|
||||
g_notification_service.push_error("CREATOR_STORAGE_SAVE_JOB"_T.data(),
|
||||
"CREATOR_STORAGE_CANNOT_OBTAIN_JSON"_T.data());
|
||||
return;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace big
|
||||
file_out << j.dump(4);
|
||||
file_out.close();
|
||||
|
||||
g_notification_service->push_success("GUI_TAB_CUSTOM_TELEPORT"_T.data(), std::format("Succesfully saved location {}", t.name));
|
||||
g_notification_service.push_success("GUI_TAB_CUSTOM_TELEPORT"_T.data(), std::format("Succesfully saved location {}", t.name));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace big
|
||||
|
||||
struct navigation_struct
|
||||
{
|
||||
char name[48] = "";
|
||||
char name[80] = "";
|
||||
std::function<void()> func = nullptr;
|
||||
std::map<tabs, navigation_struct> sub_nav{};
|
||||
rage::joaat_t hash = rage::joaat(name);
|
||||
|
@ -22,107 +22,92 @@ namespace big
|
||||
|
||||
void model_preview_service::show_ped(Hash hash)
|
||||
{
|
||||
m_ped_clone = 0;
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && m_ped_model_hash != hash)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ped_model_hash != hash)
|
||||
if (!m_running)
|
||||
{
|
||||
m_ped_model_hash = hash;
|
||||
|
||||
if (m_ped_model_hash != 0)
|
||||
{
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
void model_preview_service::show_ped(Hash hash, Ped clone)
|
||||
{
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && (m_ped_model_hash != hash || m_ped_clone != clone ))
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ped_model_hash != hash || m_ped_clone != clone)
|
||||
if (!m_running)
|
||||
{
|
||||
m_ped_model_hash = hash;
|
||||
m_ped_clone = clone;
|
||||
|
||||
if (m_ped_model_hash != 0)
|
||||
{
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
m_ped_clone = clone;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle(Hash hash, bool spawn_max)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && m_veh_model_hash != hash)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_veh_model_hash != hash || m_veh_spawn_max != spawn_max)
|
||||
if (!m_running)
|
||||
{
|
||||
m_veh_model_hash = hash;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_model_hash != 0)
|
||||
{
|
||||
m_veh_spawn_max = spawn_max;
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle(const std::map<int, int32_t>& owned_mods, bool spawn_max)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_spawn_max != spawn_max || m_veh_owned_mods.size() != owned_mods.size()
|
||||
|| !std::equal(m_veh_owned_mods.begin(), m_veh_owned_mods.end(), owned_mods.begin()))
|
||||
if (m_running && m_veh_owned_mods != owned_mods)
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_running)
|
||||
{
|
||||
auto hash_item = owned_mods.find(MOD_MODEL_HASH);
|
||||
|
||||
m_veh_model_hash = hash_item->second;
|
||||
|
||||
if (m_veh_model_hash != 0)
|
||||
{
|
||||
m_veh_owned_mods.insert(owned_mods.begin(), owned_mods.end());
|
||||
m_veh_spawn_max = spawn_max;
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
m_veh_owned_mods.insert(owned_mods.begin(), owned_mods.end());
|
||||
m_veh_spawn_max = spawn_max;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle_persisted(std::string vehicle_name)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_veh_model_hash = 0;
|
||||
|
||||
if (m_current_persisted_vehicle_name != vehicle_name)
|
||||
if (m_running && m_current_persisted_vehicle_name != vehicle_name)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_running)
|
||||
{
|
||||
m_current_persisted_vehicle_name = vehicle_name;
|
||||
m_new_model = true;
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
|
||||
void model_preview_service::preview_loop()
|
||||
{
|
||||
if (m_running || m_loop_running)
|
||||
if (m_running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -130,26 +115,15 @@ namespace big
|
||||
m_running = true;
|
||||
|
||||
g_fiber_pool->queue_job([this] {
|
||||
m_loop_running = true;
|
||||
m_heading = 0.f;
|
||||
m_rotation_start_time = std::chrono::steady_clock::now();
|
||||
|
||||
while (g_running && m_running && g_gui->is_open() && (m_ped_model_hash || m_veh_model_hash || !m_current_persisted_vehicle_name.empty()))
|
||||
while (!m_shutdown_preview && g_running && g_gui->is_open() )
|
||||
{
|
||||
Vector3 location;
|
||||
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 5.f, -.5f);
|
||||
}
|
||||
else if (m_veh_model_hash || !m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f);
|
||||
}
|
||||
Vector3 location{};
|
||||
|
||||
if (m_current_ent == 0)
|
||||
{
|
||||
m_new_model = false;
|
||||
location.z = -10.f;
|
||||
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
m_current_ent = ped::spawn(ePedType::PED_TYPE_ARMY, m_ped_model_hash, m_ped_clone, location, 0.f, false);
|
||||
@ -172,7 +146,7 @@ namespace big
|
||||
}
|
||||
else if (!m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
m_current_ent = persist_car_service::load_vehicle(m_current_persisted_vehicle_name, g.persist_car.persist_vehicle_sub_folder, Vector3());
|
||||
m_current_ent = persist_car_service::preview_vehicle(m_current_persisted_vehicle_name, g.persist_car.persist_vehicle_sub_folder, location);
|
||||
}
|
||||
|
||||
if (m_current_ent)
|
||||
@ -189,44 +163,56 @@ namespace big
|
||||
OBJECT::SET_OBJECT_ALLOW_LOW_LOD_BUOYANCY(m_current_ent, false);
|
||||
}
|
||||
}
|
||||
else if (m_new_model)
|
||||
{
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (const int alpha = ENTITY::GET_ENTITY_ALPHA(m_current_ent); alpha < 255)
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
ENTITY::SET_ENTITY_ALPHA(m_current_ent, std::min<int>(255, alpha + 20), false);
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 5.f, -.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f);
|
||||
}
|
||||
|
||||
ENTITY::SET_ENTITY_HEADING(m_current_ent, m_heading);
|
||||
ENTITY::SET_ENTITY_COORDS(m_current_ent, location.x, location.y, location.z, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (m_heading += 0.5f; m_heading > 359)
|
||||
if (auto alpha = ENTITY::GET_ENTITY_ALPHA(m_current_ent); alpha < 255)
|
||||
{
|
||||
m_heading = 0;
|
||||
ENTITY::SET_ENTITY_ALPHA(m_current_ent, std::min<int>(255, alpha + 20), false);
|
||||
}
|
||||
|
||||
script::get_current()->yield(15ms);
|
||||
ENTITY::SET_ENTITY_HEADING(m_current_ent, m_heading);
|
||||
ENTITY::SET_ENTITY_COORDS(m_current_ent, location.x, location.y, location.z, 0, 0, 0, 0);
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_rotation_start_time).count() / 1000.0; // Convert to seconds
|
||||
|
||||
m_heading = (elapsed_time / 10.0) * 360.0; // Rotate 360 degrees every 10 seconds
|
||||
m_heading = fmod(m_heading, 360.0); // Ensure rotation is always between 0 and 360
|
||||
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
ENTITY::DELETE_ENTITY(&m_current_ent);
|
||||
|
||||
m_current_ent = 0;
|
||||
m_ped_model_hash = 0;
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
m_running = false;
|
||||
m_loop_running = false;
|
||||
clear_data();
|
||||
});
|
||||
}
|
||||
|
||||
void model_preview_service::clear_data()
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
m_ped_model_hash = {};
|
||||
m_veh_model_hash = {};
|
||||
m_ped_clone = {};
|
||||
m_current_persisted_vehicle_name = {};
|
||||
m_shutdown_preview = false;
|
||||
m_running = false;
|
||||
m_current_ent = NULL;
|
||||
}
|
||||
|
||||
void model_preview_service::stop_preview()
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
m_running = false;
|
||||
if (m_running)
|
||||
m_shutdown_preview = true;
|
||||
}
|
||||
}
|
||||
|
@ -5,25 +5,21 @@ namespace big
|
||||
{
|
||||
class model_preview_service
|
||||
{
|
||||
std::condition_variable m_cond;
|
||||
std::mutex m_mutex;
|
||||
Entity m_current_ent{};
|
||||
float m_heading{};
|
||||
|
||||
Entity m_current_ent = 0;
|
||||
Hash m_ped_model_hash{};
|
||||
Hash m_veh_model_hash{};
|
||||
Ped m_ped_clone{};
|
||||
std::string m_current_persisted_vehicle_name;
|
||||
|
||||
Hash m_veh_model_hash = 0;
|
||||
std::map<int, int32_t> m_veh_owned_mods;
|
||||
bool m_veh_spawn_max = false;
|
||||
|
||||
Hash m_ped_model_hash = 0;
|
||||
Ped m_ped_clone = 0;
|
||||
|
||||
bool m_new_model = false;
|
||||
float m_heading = 0.f;
|
||||
bool m_loop_running = false;
|
||||
bool m_running = false;
|
||||
|
||||
std::string m_current_persisted_vehicle_name;
|
||||
bool m_running = false;
|
||||
bool m_shutdown_preview = false;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_rotation_start_time;
|
||||
public:
|
||||
model_preview_service();
|
||||
~model_preview_service();
|
||||
@ -35,9 +31,11 @@ namespace big
|
||||
void show_vehicle(const std::map<int, int32_t>& owned_mods, bool spawn_max);
|
||||
void show_vehicle_persisted(std::string vehicle_name);
|
||||
void show_vehicle(Vehicle veh);
|
||||
|
||||
void preview_loop();
|
||||
void stop_preview();
|
||||
|
||||
private:
|
||||
void clear_data();
|
||||
void preview_loop();
|
||||
};
|
||||
|
||||
inline model_preview_service* g_model_preview_service{};
|
||||
|
46
src/services/notifications/notification.cpp
Normal file
46
src/services/notifications/notification.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "notification.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
notification::notification(const std::string title, const std::string message, NotificationType type, const std::chrono::high_resolution_clock::duration lifetime) :
|
||||
m_title(title),
|
||||
m_message(message),
|
||||
m_identifier(std::hash<std::string>{}(title + message)),
|
||||
m_type(type),
|
||||
m_lifetime(lifetime),
|
||||
m_destroy_time(std::chrono::high_resolution_clock::now() + lifetime),
|
||||
m_counter(1)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NotificationType::DANGER: m_color = ImVec4(0.69f, 0.29f, 0.29f, 1.00f); break;
|
||||
case NotificationType::WARNING: m_color = ImVec4(0.69f, 0.49f, 0.29f, 1.00f); break;
|
||||
case NotificationType::SUCCESS: m_color = ImVec4(0.29f, 0.69f, 0.34f, 1.00f); break;
|
||||
default:
|
||||
case NotificationType::INFO: m_color = ImVec4(0.80f, 0.80f, 0.83f, 1.00f); break;
|
||||
}
|
||||
}
|
||||
|
||||
// linear fade out in the last 600ms
|
||||
const float notification::alpha() const
|
||||
{
|
||||
const auto remaining_time = std::chrono::duration_cast<std::chrono::milliseconds>(m_destroy_time - std::chrono::high_resolution_clock::now());
|
||||
if (remaining_time < 300ms)
|
||||
{
|
||||
return (float)remaining_time.count() / 300.f;
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void notification::reset()
|
||||
{
|
||||
++m_counter;
|
||||
|
||||
m_destroy_time = std::chrono::high_resolution_clock::now() + m_lifetime;
|
||||
}
|
||||
|
||||
bool notification::should_be_destroyed() const
|
||||
{
|
||||
return m_destroy_time < std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
}
|
89
src/services/notifications/notification.hpp
Normal file
89
src/services/notifications/notification.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
enum class NotificationType
|
||||
{
|
||||
INFO,
|
||||
SUCCESS,
|
||||
WARNING,
|
||||
DANGER,
|
||||
};
|
||||
|
||||
class notification
|
||||
{
|
||||
private:
|
||||
std::string m_title;
|
||||
std::string m_message;
|
||||
std::size_t m_identifier;
|
||||
|
||||
NotificationType m_type;
|
||||
|
||||
std::chrono::high_resolution_clock::duration m_lifetime;
|
||||
std::chrono::steady_clock::time_point m_destroy_time;
|
||||
|
||||
ImVec4 m_color;
|
||||
std::size_t m_counter;
|
||||
|
||||
public:
|
||||
notification() = default;
|
||||
virtual ~notification() = default;
|
||||
notification(const notification&) = default;
|
||||
notification(notification&&) noexcept = default;
|
||||
notification& operator=(const notification&) = default;
|
||||
notification& operator=(notification&&) noexcept = default;
|
||||
|
||||
notification(const std::string title, const std::string message, NotificationType type, const std::chrono::high_resolution_clock::duration lifetime = std::chrono::seconds(5));
|
||||
|
||||
const std::string& title() const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
const std::string& message() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
const std::size_t identifier() const
|
||||
{
|
||||
return m_identifier;
|
||||
}
|
||||
|
||||
const NotificationType type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
const std::chrono::steady_clock::time_point destroy_time() const
|
||||
{
|
||||
return m_destroy_time;
|
||||
}
|
||||
|
||||
const float alpha() const;
|
||||
const ImVec4 color() const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of times the notification was refreshed because the same notification was pushed.
|
||||
*
|
||||
* @return const std::size_t
|
||||
*/
|
||||
const std::size_t counter() const
|
||||
{
|
||||
return m_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the destroy timer on a notification, extending its lifetime and incrementing the show counter.
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* @brief Indicates if the notification is ready to be destroyed (it has gone past its lifetime).
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool should_be_destroyed() const;
|
||||
};
|
||||
}
|
@ -4,69 +4,64 @@
|
||||
|
||||
namespace big
|
||||
{
|
||||
notification_service::notification_service()
|
||||
bool notification_service::initialise()
|
||||
{
|
||||
push("NOTIFICATION_WELCOME_TITLE"_T.data(),
|
||||
std::vformat("NOTIFICATION_WELCOME_TEXT"_T, std::make_format_args(ImGui::key_names[g.settings.hotkeys.menu_toggle])));
|
||||
|
||||
g_notification_service = this;
|
||||
}
|
||||
|
||||
notification_service::~notification_service()
|
||||
{
|
||||
g_notification_service = nullptr;
|
||||
}
|
||||
|
||||
void notification_service::push(notification n)
|
||||
{
|
||||
this->notifications.emplace(std::hash<std::string>{}(n.message + n.title), n);
|
||||
return true;
|
||||
}
|
||||
|
||||
void notification_service::push(const std::string& title, const std::string& message)
|
||||
{
|
||||
this->push({NotificationType::INFO, title, message, std::chrono::system_clock::now(), 5000.f, 1.f});
|
||||
push({title, message, NotificationType::INFO});
|
||||
}
|
||||
|
||||
void notification_service::push_warning(const std::string& title, const std::string& message)
|
||||
{
|
||||
this->push({NotificationType::WARNING, title, message, std::chrono::system_clock::now(), 7000.f, 1.f});
|
||||
push({title, message, NotificationType::WARNING, 7s});
|
||||
}
|
||||
|
||||
void notification_service::push_error(const std::string& title, const std::string& message)
|
||||
{
|
||||
this->push({NotificationType::DANGER, title, message, std::chrono::system_clock::now(), 7000.f, 1.f});
|
||||
push({title, message, NotificationType::DANGER, 7s});
|
||||
}
|
||||
|
||||
void notification_service::push_success(const std::string& title, const std::string& message)
|
||||
{
|
||||
this->push({NotificationType::SUCCESS, title, message, std::chrono::system_clock::now(), 7000.f, 1.f});
|
||||
push({title, message, NotificationType::SUCCESS, 7s});
|
||||
}
|
||||
|
||||
std::vector<notification> notification_service::get()
|
||||
{
|
||||
std::vector<notification> notifications_to_sent;
|
||||
std::vector<std::size_t> to_remove;
|
||||
for (auto& n : this->notifications)
|
||||
// remove old notifications
|
||||
for (auto it = m_notifications.begin(); it != m_notifications.end();)
|
||||
{
|
||||
std::chrono::time_point<std::chrono::system_clock> curTime = std::chrono::system_clock::now();
|
||||
const float time_diff =
|
||||
(float)std::chrono::duration_cast<std::chrono::milliseconds>(curTime - n.second.created_on).count();
|
||||
n.second.alpha = 1;
|
||||
if (n.second.destroy_in <= time_diff)
|
||||
if (it->second.should_be_destroyed())
|
||||
{
|
||||
n.second.alpha = 1.f - ((time_diff - n.second.destroy_in) / 600);
|
||||
n.second.alpha = n.second.alpha < 0.f ? 0.f : n.second.alpha;
|
||||
it = m_notifications.erase(it++);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.second.alpha > 0.f)
|
||||
notifications_to_sent.push_back(n.second);
|
||||
else
|
||||
to_remove.push_back(n.first);
|
||||
++it;
|
||||
}
|
||||
for (std::size_t k : to_remove)
|
||||
this->notifications.erase(k);
|
||||
|
||||
return notifications_to_sent;
|
||||
// grab only the notifications, no need for the keys
|
||||
auto sorted = m_notifications | std::views::values | std::ranges::to<std::vector<notification>>();
|
||||
std::sort(sorted.begin(), sorted.end(), [](auto const& a, auto const& b) {
|
||||
// inverse sorting, highest remaining time goes to top
|
||||
return a.destroy_time() > b.destroy_time();
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
|
||||
}
|
||||
void notification_service::push(notification n)
|
||||
{
|
||||
const auto [pair, inserted] = m_notifications.insert({n.identifier(), n});
|
||||
if (!inserted)
|
||||
{
|
||||
pair->second.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,46 +1,31 @@
|
||||
#pragma once
|
||||
#include "notification.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
enum class NotificationType
|
||||
{
|
||||
INFO,
|
||||
SUCCESS,
|
||||
WARNING,
|
||||
DANGER,
|
||||
};
|
||||
|
||||
struct notification
|
||||
{
|
||||
NotificationType type;
|
||||
const std::string title;
|
||||
const std::string message;
|
||||
const std::chrono::time_point<std::chrono::system_clock> created_on;
|
||||
const float destroy_in;
|
||||
float alpha;
|
||||
};
|
||||
|
||||
class notification_service final
|
||||
{
|
||||
std::unordered_map<std::size_t, notification> notifications;
|
||||
std::unordered_map<std::size_t, notification> m_notifications;
|
||||
|
||||
public:
|
||||
notification_service();
|
||||
virtual ~notification_service();
|
||||
notification_service() = default;
|
||||
virtual ~notification_service() = default;
|
||||
|
||||
void push(notification);
|
||||
void push(const std::string&, const std::string&);
|
||||
void push_warning(const std::string&, const std::string&);
|
||||
void push_error(const std::string&, const std::string&);
|
||||
void push_success(const std::string&, const std::string&);
|
||||
bool initialise();
|
||||
|
||||
void push(const std::string& title, const std::string& message);
|
||||
void push_warning(const std::string& title, const std::string& message);
|
||||
void push_error(const std::string& title, const std::string& message);
|
||||
void push_success(const std::string& title, const std::string& message);
|
||||
|
||||
// cleans up old notifications from the map and returns a sorted list based on the destroy time
|
||||
std::vector<notification> get();
|
||||
|
||||
std::map<NotificationType, ImVec4> notification_colors = {
|
||||
{NotificationType::INFO, ImVec4(0.80f, 0.80f, 0.83f, 1.00f)},
|
||||
{NotificationType::SUCCESS, ImVec4(0.29f, 0.69f, 0.34f, 1.00f)},
|
||||
{NotificationType::WARNING, ImVec4(0.69f, 0.49f, 0.29f, 1.00f)},
|
||||
{NotificationType::DANGER, ImVec4(0.69f, 0.29f, 0.29f, 1.00f)},
|
||||
};
|
||||
private:
|
||||
void push(notification notification);
|
||||
|
||||
};
|
||||
|
||||
inline notification_service* g_notification_service{};
|
||||
}
|
||||
inline notification_service g_notification_service{};
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ namespace big
|
||||
file_out << j.dump(4);
|
||||
file_out.close();
|
||||
|
||||
g_notification_service->push_success("Animations", std::format("Succesfully saved location {}", p.name));
|
||||
g_notification_service.push_success("Animations", std::format("Succesfully saved location {}", p.name));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -177,4 +177,4 @@ namespace big
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ namespace big
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
g_notification_service->push_warning("Persist Weapons", "Failed to load JSON file from disk.");
|
||||
g_notification_service.push_warning("Persist Weapons", "Failed to load JSON file from disk.");
|
||||
LOG(WARNING) << "Persist Weapons failed to load JSON file: " << g.persist_weapons.weapon_loadout_file << " because " << e.what();
|
||||
}
|
||||
}
|
||||
@ -193,4 +193,4 @@ namespace big
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,24 +35,24 @@ namespace big
|
||||
|
||||
if (g.player_db.notify_when_joinable && !is_joinable_session(player.session_type) && is_joinable_session(new_session_type))
|
||||
{
|
||||
g_notification_service->push_success("Player DB", std::format("{} is now in a joinable session", player.name));
|
||||
g_notification_service.push_success("Player DB", std::format("{} is now in a joinable session", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_online && (player.session_type == GSType::Invalid || player.session_type == GSType::Unknown) && new_session_type != GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push_success("Player DB", std::format("{} is now online", player.name));
|
||||
g_notification_service.push_success("Player DB", std::format("{} is now online", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_unjoinable && is_joinable_session(player.session_type) && !is_joinable_session(new_session_type) && new_session_type != GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is no longer in a joinable session", player.name));
|
||||
g_notification_service.push("Player DB", std::format("{} is no longer in a joinable session", player.name));
|
||||
}
|
||||
else if (g.player_db.notify_when_offline && player.session_type != GSType::Invalid && player.session_type != GSType::Unknown && new_session_type == GSType::Invalid)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is no longer online", player.name));
|
||||
g_notification_service.push("Player DB", std::format("{} is no longer online", player.name));
|
||||
}
|
||||
|
||||
if (g.player_db.notify_on_session_type_change && (int)new_session_type >= (int)GSType::InviteOnly && (int)new_session_type < (int)GSType::Max)
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is now in a{} {} session", player.name, new_session_type == GSType::InviteOnly ? "n" : "", get_session_type_str(new_session_type)));
|
||||
g_notification_service.push("Player DB", std::format("{} is now in a{} {} session", player.name, new_session_type == GSType::InviteOnly ? "n" : "", get_session_type_str(new_session_type)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,14 +64,14 @@ namespace big
|
||||
|
||||
if (new_game_mode == GameMode::None && old_game_mode != GameMode::None && old_game_mode_str != "None")
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is no longer in a {}", player->name, old_game_mode_str));
|
||||
g_notification_service.push("Player DB", std::format("{} is no longer in a {}", player->name, old_game_mode_str));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!can_fetch_name(new_game_mode))
|
||||
{
|
||||
if (new_game_mode_str != "None")
|
||||
g_notification_service->push("Player DB", std::format("{} is now in a {}", player->name, new_game_mode_str));
|
||||
g_notification_service.push("Player DB", std::format("{} is now in a {}", player->name, new_game_mode_str));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -83,11 +83,11 @@ namespace big
|
||||
|
||||
if (mission_name.empty())
|
||||
{
|
||||
g_notification_service->push("Player DB", std::format("{} is now in a {}", player->name, new_game_mode_str));
|
||||
g_notification_service.push("Player DB", std::format("{} is now in a {}", player->name, new_game_mode_str));
|
||||
return;
|
||||
}
|
||||
|
||||
g_notification_service->push("Player DB", std::format("{} has joined the {} \"{}\"", player->name, new_game_mode_str, mission_name));
|
||||
g_notification_service.push("Player DB", std::format("{} has joined the {} \"{}\"", player->name, new_game_mode_str, mission_name));
|
||||
player->game_mode_name = mission_name;
|
||||
}
|
||||
|
||||
@ -413,7 +413,7 @@ namespace big
|
||||
else if (it->second->notify_online && it->second->session_id != info.m_session_token
|
||||
&& g.player_db.notify_on_session_change)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} has joined a new session", it->second->name));
|
||||
}
|
||||
|
||||
@ -424,12 +424,12 @@ namespace big
|
||||
{
|
||||
if (is_spectating)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} is now spectating", it->second->name));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} is no longer spectating", it->second->name));
|
||||
}
|
||||
}
|
||||
@ -437,7 +437,7 @@ namespace big
|
||||
if (it->second->notify_online && is_host_of_session != it->second->is_host_of_session
|
||||
&& g.player_db.notify_on_become_host && is_host_of_session && it->second->session_id == info.m_session_token)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} is now the host of their session", it->second->name));
|
||||
}
|
||||
|
||||
@ -446,19 +446,19 @@ namespace big
|
||||
{
|
||||
if (is_host_of_transition_session)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} has hosted a job lobby", it->second->name));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} has joined a job lobby", it->second->name));
|
||||
}
|
||||
}
|
||||
else if (it->second->notify_online && g.player_db.notify_on_transition_change
|
||||
&& transition_info.m_session_token == -1 && it->second->transition_session_id != -1)
|
||||
{
|
||||
g_notification_service->push("Player DB",
|
||||
g_notification_service.push("Player DB",
|
||||
std::format("{} is no longer in a job lobby", it->second->name));
|
||||
}
|
||||
|
||||
@ -549,4 +549,4 @@ namespace big
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ namespace big
|
||||
static auto reset_spawn_pos_to_offset = [&]() -> void {
|
||||
Ped player_ped_handle = g_pointers->m_gta.m_ptr_to_handle(s.target->get_ped());
|
||||
s.m_spawn_pos = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(player_ped_handle, 0, -7, 0);
|
||||
g_notification_service->push_warning("Squad Spawner", "No suitable spot found, spawning at an offset");
|
||||
g_notification_service.push_warning("Squad Spawner", "No suitable spot found, spawning at an offset");
|
||||
};
|
||||
|
||||
static auto is_pos_valid = [&]() -> bool {
|
||||
@ -206,7 +206,7 @@ namespace big
|
||||
|
||||
if (!s.target->get_net_game_player() || s.m_squad_size < 1 || !STREAMING::IS_MODEL_VALID(rage::joaat(s.m_ped_model)))
|
||||
{
|
||||
g_notification_service->push_error("Squad spawner", "Error spawning squad");
|
||||
g_notification_service.push_error("Squad spawner", "Error spawning squad");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ namespace big
|
||||
if (VEHICLE::GET_VEHICLE_MODEL_NUMBER_OF_SEATS(veh_model_hash) < s.m_squad_size)
|
||||
{
|
||||
s.m_squad_size = VEHICLE::GET_VEHICLE_MODEL_NUMBER_OF_SEATS(veh_model_hash);
|
||||
g_notification_service->push_warning("Squad Spawner", "The squad vehicle has insufficient seats, decreasing the squad size");
|
||||
g_notification_service.push_warning("Squad Spawner", "The squad vehicle has insufficient seats, decreasing the squad size");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace big
|
||||
{
|
||||
write << std::setw(4) << j << std::endl;
|
||||
write.close();
|
||||
g_notification_service->push_success("Squad spawner", std::string("Succesfully saved ").append(s.m_name));
|
||||
g_notification_service.push_success("Squad spawner", std::string("Succesfully saved ").append(s.m_name));
|
||||
fetch_squads();
|
||||
return true;
|
||||
}
|
||||
@ -101,4 +101,4 @@ namespace big
|
||||
m_templates.push_back(squad("Mobile squad", "s_m_m_highsec_01", "WEAPON_MICROSMG", "komoda", 4, false, false, ped_proofs, 0, 0, 0, 100, eSquadSpawnDistance::FAR_AWAY, eCombatAbilityLevel::PROFESSIONAL, true, true, "This squad makes use of 'Vehicle catchup'"));
|
||||
m_templates.push_back(squad("Altruists", "a_m_m_acult_01", "WEAPON_SNSPISTOL", "", 8, false, false, ped_proofs, 0, 0, 0, 100, eSquadSpawnDistance::CLOSEBY, eCombatAbilityLevel::PROFESSIONAL, false, false, "Cannibals from the alrtuist cult will surround the victim using 'Disperse'", true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
{
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(vehicle) || !ENTITY::IS_ENTITY_A_VEHICLE(vehicle))
|
||||
{
|
||||
g_notification_service->push_warning("PERSIST_CAR_TITLE"_T.data(),
|
||||
g_notification_service.push_warning("PERSIST_CAR_TITLE"_T.data(),
|
||||
"PERSIST_CAR_INVALID_VEHICLE_SAVE_ATTEMPT"_T.data());
|
||||
return;
|
||||
}
|
||||
@ -27,6 +27,28 @@ namespace big
|
||||
file_stream.close();
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::preview_vehicle(std::string_view file_name, std::string folder_name, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
||||
|
||||
std::ifstream file_stream(file.get_path());
|
||||
|
||||
nlohmann::json vehicle_json;
|
||||
|
||||
try
|
||||
{
|
||||
file_stream >> vehicle_json;
|
||||
file_stream.close();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
g_notification_service.push_warning("PERSIST_CAR_TITLE"_T.data(), "Failed to load JSON file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return spawn_vehicle_json(vehicle_json, self::ped, spawn_coords, true);
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::load_vehicle(std::string_view file_name, std::string folder_name, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
||||
@ -42,7 +64,7 @@ namespace big
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
g_notification_service->push_warning("PERSIST_CAR_TITLE"_T.data(), "Failed to load JSON file");
|
||||
g_notification_service.push_warning("PERSIST_CAR_TITLE"_T.data(), "Failed to load JSON file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -188,16 +210,16 @@ namespace big
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords)
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords, bool is_preview)
|
||||
{
|
||||
const Hash vehicle_hash = vehicle_json[vehicle_model_hash_key];
|
||||
const Vector3& spawn_location = spawn_coords.has_value() ? spawn_coords.value() : vehicle::get_spawn_location(g.persist_car.spawn_inside, vehicle_hash);
|
||||
const float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
Vehicle vehicle = self::veh;
|
||||
if (spawn_coords.has_value() || (!spawn_coords.has_value() && ENTITY::GET_ENTITY_MODEL(vehicle) != vehicle_hash))
|
||||
if (is_preview || (!is_preview && ENTITY::GET_ENTITY_MODEL(vehicle) != vehicle_hash))
|
||||
{
|
||||
vehicle = big::vehicle::spawn(vehicle_hash, spawn_location, spawn_heading);
|
||||
vehicle = big::vehicle::spawn(vehicle_hash, spawn_location, spawn_heading, !is_preview);
|
||||
|
||||
if (spawn_location.x + spawn_location.y + spawn_location.z != 0)
|
||||
script::get_current()->yield(); //This is needed to wait for the engine to instantiate things like the radio station so it won't overwrite it on the next frame.
|
||||
|
@ -13,6 +13,7 @@ namespace big
|
||||
static Vehicle clone_ped_car(Ped ped, Vehicle vehicle);
|
||||
static void save_vehicle(Vehicle vehicle, std::string_view file_name, std::string folder_name);
|
||||
static Vehicle load_vehicle(std::string_view file_name, std::string folder_name = "", const std::optional<Vector3>& = std::nullopt);
|
||||
static Vehicle preview_vehicle(std::string_view file_name, std::string folder_name = "", const std::optional<Vector3>& = std::nullopt);
|
||||
static void delete_vehicle(std::string_view file_name, std::string folder_name);
|
||||
|
||||
private:
|
||||
@ -68,7 +69,7 @@ namespace big
|
||||
|
||||
static Vehicle spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
static Vehicle spawn_vehicle(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt, bool is_preview = false);
|
||||
|
||||
static nlohmann::json get_full_vehicle_json(Vehicle vehicle);
|
||||
|
||||
|
@ -172,7 +172,7 @@ namespace big
|
||||
4.f,
|
||||
5.f);
|
||||
//LOG(INFO) << "Navmesh probably failed, issiuing regular task ";
|
||||
g_notification_service->push_warning("VEHICLE_CONTROLLER"_T.data(),
|
||||
g_notification_service.push_warning("VEHICLE_CONTROLLER"_T.data(),
|
||||
"VEHICLE_CONTROLLER_TRY_ALT_PATHFINDING"_T.data());
|
||||
script::get_current()->yield(500ms);
|
||||
}
|
||||
@ -308,13 +308,13 @@ namespace big
|
||||
if (vehicle_control::find_suitable_destination_near_player(destination, heading))
|
||||
{
|
||||
//LOG(INFO) << "Suitable destination found";
|
||||
g_notification_service->push_success("VEHICLE_CONTROLLER"_T.data(),
|
||||
g_notification_service.push_success("VEHICLE_CONTROLLER"_T.data(),
|
||||
"VEHICLE_CONTROLLER_FOUND_LOCATION"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
//LOG(INFO) << "Couldn't find suitable destionation, defaulting to offset of player\nThis might go wrong";
|
||||
g_notification_service->push_error("VEHICLE_CONTROLLER"_T.data(),
|
||||
g_notification_service.push_error("VEHICLE_CONTROLLER"_T.data(),
|
||||
"VEHICLE_CONTROLLER_FORCE_PATHFINDING"_T.data());
|
||||
destination = behind_pos;
|
||||
}
|
||||
@ -338,7 +338,7 @@ namespace big
|
||||
else
|
||||
{
|
||||
//LOG(INFO) << "Navmesh load failed";
|
||||
g_notification_service->push_error("VEHICLE_CONTROLLER"_T.data(), "VEHICLE_CONTROLLER_NAVMESH_FAILURE"_T.data());
|
||||
g_notification_service.push_error("VEHICLE_CONTROLLER"_T.data(), "VEHICLE_CONTROLLER_NAVMESH_FAILURE"_T.data());
|
||||
m_driver_performing_task = false;
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ namespace big::animations
|
||||
if (!std::filesystem::exists(g_file_manager.get_project_file("animDictsCompact.json").get_path()))
|
||||
{
|
||||
LOG(WARNING) << "Animations file is not in directory. https://raw.githubusercontent.com/DurtyFree/gta-v-data-dumps/master/animDictsCompact.json";
|
||||
g_notification_service->push_warning("Animations", "Please download the appropriate animations json and put it in the mod directory.");
|
||||
g_notification_service.push_warning("Animations", "Please download the appropriate animations json and put it in the mod directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -120,4 +120,4 @@ namespace big::animations
|
||||
LOG(WARNING) << "Failed fetching all anims: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
253
src/util/chat.hpp
Normal file
253
src/util/chat.hpp
Normal file
@ -0,0 +1,253 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "core/enums.hpp"
|
||||
|
||||
#include "packet.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
#include <script/HudColor.hpp>
|
||||
#include <network/ChatData.hpp>
|
||||
#include <script/globals/GPBD_FM_3.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
static void gamer_handle_serialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
||||
{
|
||||
buf.Write<uint8_t>(hnd.m_platform, sizeof(hnd.m_platform) * 8);
|
||||
if (hnd.m_platform == rage::rlPlatforms::PC)
|
||||
{
|
||||
buf.WriteRockstarId(hnd.m_rockstar_id);
|
||||
buf.Write<uint8_t>(hnd.m_padding, sizeof(hnd.m_padding) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* spam_texts[] =
|
||||
{
|
||||
"qq", //a chinese chat app
|
||||
"QQ",
|
||||
"WWW.",
|
||||
"www.",
|
||||
".cn",
|
||||
".CN",
|
||||
".cc",
|
||||
".CC",
|
||||
".TOP",
|
||||
".COM",
|
||||
".top",
|
||||
"\xE3\x80\x90", //left bracket in Chinese input method
|
||||
"/Menu",
|
||||
"Money/",
|
||||
"Money\\\\",
|
||||
"Money\\",
|
||||
".gg",
|
||||
"--->",
|
||||
"shopgta5",
|
||||
"doit#",
|
||||
"krutka#",
|
||||
"<b>",
|
||||
"P888",
|
||||
"gtacash",
|
||||
"\xE6\x89\xA3\xE6\x89\xA3", // no clue what this is
|
||||
"\xE5\xBE\xAE\xE4\xBF\xA1", // "wechat" in Chinese
|
||||
".cc",
|
||||
"<font s",
|
||||
"sellix.io",
|
||||
"ezcars",
|
||||
"PLANO INICIAL", // "initial plan"
|
||||
"REP +",
|
||||
"20R$", // Brazil currency?
|
||||
"l55.me",
|
||||
"\xE5\xBA\x97", //"shop" in Chinese
|
||||
"\xE9\x92\xB1", //"money" in Chinese
|
||||
"\xE5\x88\xB7", //"make(money)" in Chinese
|
||||
"\xE8\x90\x9D\xE8\x8E\x89", // "cute girl" in Chinese
|
||||
"\xE5\xA6\x88", // "mother" in Chinese
|
||||
"\xE7\xBE\x8E\xE5\xA5\xB3", // "sexy girl" in Chinese
|
||||
"\xE5\xBC\xBA\xE5\xA5\xB8", // "rape" in Chinese
|
||||
"\xE8\x90\x9D", // "loli" in Chinese
|
||||
"\xE6\x8C\x82", // "hack" in Chinese
|
||||
"\xE5\x85\x83", // chinese dollar
|
||||
"\xE9\x98\xB4\xE4\xBC\xA0\xE5\xAA\x92", // "Yin Media" in Chinese
|
||||
"\xE7\xBD\x91\xE7\xBA\xA2", // "internet celebrities" in Chinese
|
||||
"TRUSTPILOT",
|
||||
"cashlounge",
|
||||
"Fast Delivery",
|
||||
"yosativa",
|
||||
"rich2day",
|
||||
"LevelLifters",
|
||||
". com",
|
||||
"$1,000,000,000",
|
||||
"Instant Delivery",
|
||||
"0 Ban Risk",
|
||||
"Discord For Cheap Money",
|
||||
"10-30m",
|
||||
"Discord todo",
|
||||
};
|
||||
}
|
||||
|
||||
namespace big::chat
|
||||
{
|
||||
inline SpamReason is_text_spam(const char* text, player_ptr player)
|
||||
{
|
||||
if (g.session.use_spam_timer)
|
||||
{
|
||||
if (player->last_message_time.has_value())
|
||||
{
|
||||
auto currentTime = std::chrono::steady_clock::now();
|
||||
auto diff = std::chrono::duration_cast<std::chrono::seconds>(currentTime - player->last_message_time.value());
|
||||
player->last_message_time.emplace(currentTime);
|
||||
|
||||
if (strlen(text) > g.session.spam_length && diff.count() <= g.session.spam_timer)
|
||||
return SpamReason::TIMER_DETECTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->last_message_time.emplace(std::chrono::steady_clock::now());
|
||||
}
|
||||
}
|
||||
for (auto e : spam_texts)
|
||||
if (strstr(text, e) != 0)
|
||||
return SpamReason::STATIC_DETECTION;
|
||||
|
||||
return SpamReason::NOT_A_SPAMMER;
|
||||
}
|
||||
|
||||
inline void log_chat(char* msg, player_ptr player, SpamReason spam_reason, bool is_team)
|
||||
{
|
||||
std::ofstream log(
|
||||
g_file_manager.get_project_file(spam_reason != SpamReason::NOT_A_SPAMMER ? "./spam.log" : "./chat.log").get_path(),
|
||||
std::ios::app);
|
||||
|
||||
auto& data = *player->get_net_data();
|
||||
auto ip = player->get_ip_address();
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
|
||||
auto timer = std::chrono::system_clock::to_time_t(now);
|
||||
auto local_time = *std::localtime(&timer);
|
||||
|
||||
std::string spam_reason_str = "";
|
||||
|
||||
switch (spam_reason)
|
||||
{
|
||||
case SpamReason::STATIC_DETECTION: spam_reason_str = "(Static Detection) "; break;
|
||||
case SpamReason::TIMER_DETECTION: spam_reason_str = "(Timer Detection) "; break;
|
||||
}
|
||||
|
||||
log << spam_reason_str << "[" << std::put_time(&local_time, "%m/%d/%Y %I:%M:%S") << ":" << std::setfill('0') << std::setw(3) << ms.count() << " " << std::put_time(&local_time, "%p") << "] ";
|
||||
|
||||
if (ip)
|
||||
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <" << (int)ip.value().m_field1 << "."
|
||||
<< (int)ip.value().m_field2 << "." << (int)ip.value().m_field3 << "." << (int)ip.value().m_field4 << "> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
|
||||
else
|
||||
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <UNKNOWN> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
|
||||
|
||||
log.close();
|
||||
}
|
||||
|
||||
inline void draw_chat(const char* msg, const char* player_name, bool is_team)
|
||||
{
|
||||
int scaleform = GRAPHICS::REQUEST_SCALEFORM_MOVIE("MULTIPLAYER_CHAT");
|
||||
|
||||
while (!GRAPHICS::HAS_SCALEFORM_MOVIE_LOADED(scaleform))
|
||||
script::get_current()->yield();
|
||||
|
||||
GRAPHICS::BEGIN_SCALEFORM_MOVIE_METHOD(scaleform, "ADD_MESSAGE");
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME_STRING(player_name); // player name
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_LITERAL_STRING(msg); // content
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_TEXTURE_NAME_STRING(HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(is_team ? "MP_CHAT_TEAM" : "MP_CHAT_ALL")); // scope
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(false); // teamOnly
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT((int)HudColor::HUD_COLOUR_PURE_WHITE); // eHudColour
|
||||
GRAPHICS::END_SCALEFORM_MOVIE_METHOD();
|
||||
|
||||
GRAPHICS::BEGIN_SCALEFORM_MOVIE_METHOD(scaleform, "SET_FOCUS");
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(1); // VISIBLE_STATE_DEFAULT
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0); // scopeType (unused)
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0); // scope (unused)
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME_STRING(player_name); // player
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT((int)HudColor::HUD_COLOUR_PURE_WHITE); // eHudColour
|
||||
GRAPHICS::END_SCALEFORM_MOVIE_METHOD();
|
||||
|
||||
GRAPHICS::DRAW_SCALEFORM_MOVIE_FULLSCREEN(scaleform, 255, 255, 255, 255, 0);
|
||||
|
||||
// fix broken scaleforms, when chat alrdy opened
|
||||
if (const auto chat_data = *g_pointers->m_gta.m_chat_data; chat_data && (chat_data->m_chat_open || chat_data->m_timer_two))
|
||||
HUD::CLOSE_MP_TEXT_CHAT();
|
||||
}
|
||||
|
||||
inline bool is_on_same_team(CNetGamePlayer* player)
|
||||
{
|
||||
auto target_id = player->m_player_id;
|
||||
|
||||
if (NETWORK::NETWORK_IS_ACTIVITY_SESSION())
|
||||
{
|
||||
// mission
|
||||
return PLAYER::GET_PLAYER_TEAM(target_id) == PLAYER::GET_PLAYER_TEAM(self::id);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto boss_goon = &scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[self::id].BossGoon;
|
||||
|
||||
if (boss_goon->Boss == target_id)
|
||||
return true;
|
||||
|
||||
if (boss_goon->Boss == -1)
|
||||
return false;
|
||||
|
||||
if (boss_goon->Boss != self::id)
|
||||
boss_goon = &scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[boss_goon->Boss].BossGoon; // get their structure
|
||||
|
||||
// bypass some P2Cs
|
||||
for (int i = 0; i < boss_goon->Goons.Size; i++)
|
||||
{
|
||||
if (boss_goon->Goons[i] == target_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// set target to send to a specific player
|
||||
inline void send_message(const std::string& message, player_ptr target = nullptr, bool draw = true, bool is_team = false)
|
||||
{
|
||||
if (!*g_pointers->m_gta.m_is_session_started)
|
||||
return;
|
||||
|
||||
packet msg{};
|
||||
msg.write_message(rage::eNetMessage::MsgTextMessage);
|
||||
msg.m_buffer.WriteString(message.c_str(), 256);
|
||||
gamer_handle_serialize(g_player_service->get_self()->get_net_data()->m_gamer_handle, msg.m_buffer);
|
||||
msg.write<bool>(is_team, 1);
|
||||
|
||||
|
||||
for (auto& player : g_player_service->players())
|
||||
{
|
||||
if (player.second && player.second->is_valid())
|
||||
{
|
||||
if (target && player.second != target)
|
||||
continue;
|
||||
|
||||
if (!target && is_team && !is_on_same_team(player.second->get_net_game_player()))
|
||||
continue;
|
||||
|
||||
msg.send(player.second->get_net_game_player()->m_msg_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw)
|
||||
if (rage::tlsContext::get()->m_is_script_thread_active)
|
||||
draw_chat(message.c_str(), g_player_service->get_self()->get_name(), is_team);
|
||||
else
|
||||
g_fiber_pool->queue_job([message, target, is_team] {
|
||||
draw_chat(message.c_str(), g_player_service->get_self()->get_name(), is_team);
|
||||
});
|
||||
}
|
||||
}
|
@ -26,7 +26,10 @@ namespace big::entity
|
||||
void delete_entity(Entity& ent, bool force)
|
||||
{
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(ent))
|
||||
{
|
||||
ent = NULL;
|
||||
return;
|
||||
}
|
||||
if (!force && !take_control_of(ent))
|
||||
{
|
||||
LOG(VERBOSE) << "Failed to take control of entity before deleting";
|
||||
|
@ -142,7 +142,7 @@ namespace big::mobile
|
||||
inline void summon_vehicle_by_index(int veh_idx)
|
||||
{
|
||||
if (*scr_globals::freemode_global.at(985).as<int*>() != -1)
|
||||
return g_notification_service->push_warning("Vehicle", "Mechanic is not ready to deliver a vehicle right now.");
|
||||
return g_notification_service.push_warning("Vehicle", "Mechanic is not ready to deliver a vehicle right now.");
|
||||
|
||||
if (g.clone_pv.spawn_inside && self::veh)
|
||||
TASK::CLEAR_PED_TASKS_IMMEDIATELY(PLAYER::PLAYER_PED_ID());
|
||||
@ -208,10 +208,10 @@ namespace big::mobile
|
||||
{
|
||||
*scr_globals::gun_van.as<Vector3*>() = spawn_point;
|
||||
|
||||
return g_notification_service->push_success("GUI_TAB_MOBILE"_T.data(), "REQUEST_GUN_VAN_NOTIFY_SUCCESS"_T.data());
|
||||
return g_notification_service.push_success("GUI_TAB_MOBILE"_T.data(), "REQUEST_GUN_VAN_NOTIFY_SUCCESS"_T.data());
|
||||
}
|
||||
|
||||
g_notification_service->push_warning("GUI_TAB_MOBILE"_T.data(), "REQUEST_GUN_VAN_NOTIFY_FAILED"_T.data());
|
||||
g_notification_service.push_warning("GUI_TAB_MOBILE"_T.data(), "REQUEST_GUN_VAN_NOTIFY_FAILED"_T.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
86
src/util/notify.cpp
Normal file
86
src/util/notify.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "notify.hpp"
|
||||
#include "chat.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "network/CNetGamePlayer.hpp"
|
||||
#include "network/ChatData.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
|
||||
namespace big::notify
|
||||
{
|
||||
void above_map(std::string_view text)
|
||||
{
|
||||
HUD::SET_TEXT_OUTLINE();
|
||||
HUD::BEGIN_TEXT_COMMAND_THEFEED_POST("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
|
||||
}
|
||||
|
||||
void crash_blocked(CNetGamePlayer* player, const char* crash)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
if ((g_player_service->get_by_id(player->m_player_id)->is_friend() && g.session.trust_friends)
|
||||
|| g_player_service->get_by_id(player->m_player_id)->is_trusted || g.session.trust_session)
|
||||
return;
|
||||
|
||||
if (g.reactions.crash.notify)
|
||||
g_notification_service.push_error("Protections", std::format("Blocked {} crash from {}", crash, player->get_name()));
|
||||
|
||||
if (g.reactions.crash.log)
|
||||
LOG(WARNING) << "Blocked " << crash << " crash from " << player->get_name() << " ("
|
||||
<< (player->get_net_data() ? player->get_net_data()->m_gamer_handle.m_rockstar_id : 0) << ")";
|
||||
|
||||
if (g.reactions.crash.announce_in_chat)
|
||||
{
|
||||
auto msg = std::vformat("NOTIFICATION_CRASH_TYPE_BLOCKED"_T, std::make_format_args(player->get_name(), crash));
|
||||
msg = std::format("{} {}", g.session.chat_output_prefix, msg);
|
||||
|
||||
chat::send_message(msg);
|
||||
}
|
||||
|
||||
g.reactions.crash.process_common(g_player_service->get_by_id(player->m_player_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.reactions.crash.notify)
|
||||
g_notification_service.push_error("Protections", std::format("Blocked {} crash from unknown player", crash));
|
||||
}
|
||||
}
|
||||
|
||||
// Shows a busy spinner till the value at the address equals the value passed or if timeout is hit
|
||||
void busy_spinner(std::string_view text, int* address, int value, int timeout)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_BUSYSPINNER_ON("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_BUSYSPINNER_ON(3);
|
||||
|
||||
for (size_t i = 0; *address != value && i < (size_t)timeout * 100; i++)
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
HUD::BUSYSPINNER_OFF();
|
||||
}
|
||||
|
||||
void show_subtitle(std::string_view text, int ms)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_PRINT("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_PRINT(ms, 1);
|
||||
}
|
||||
|
||||
void display_help_text(std::string_view text)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_DISPLAY_HELP("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_DISPLAY_HELP(0, 0, 1, -1);
|
||||
}
|
||||
|
||||
void player_joined(CNetGamePlayer* net_game_player)
|
||||
{
|
||||
above_map(std::format("<C>{}</C> joined.", net_game_player->get_name()));
|
||||
}
|
||||
}
|
@ -8,118 +8,22 @@
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "chat.hpp"
|
||||
|
||||
#include <script/HudColor.hpp>
|
||||
|
||||
namespace big::notify
|
||||
{
|
||||
inline void above_map(std::string_view text)
|
||||
{
|
||||
HUD::SET_TEXT_OUTLINE();
|
||||
HUD::BEGIN_TEXT_COMMAND_THEFEED_POST("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
|
||||
}
|
||||
void above_map(std::string_view text);
|
||||
|
||||
inline void draw_chat(const char* msg, const char* player_name, bool is_team)
|
||||
{
|
||||
int scaleform = GRAPHICS::REQUEST_SCALEFORM_MOVIE("MULTIPLAYER_CHAT");
|
||||
|
||||
while (!GRAPHICS::HAS_SCALEFORM_MOVIE_LOADED(scaleform))
|
||||
script::get_current()->yield();
|
||||
|
||||
GRAPHICS::BEGIN_SCALEFORM_MOVIE_METHOD(scaleform, "ADD_MESSAGE");
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME_STRING(player_name); // player name
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_LITERAL_STRING(msg); // content
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_TEXTURE_NAME_STRING(HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(is_team ? "MP_CHAT_TEAM" : "MP_CHAT_ALL")); // scope
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(false); // teamOnly
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT((int)HudColor::HUD_COLOUR_PURE_WHITE); // eHudColour
|
||||
GRAPHICS::END_SCALEFORM_MOVIE_METHOD();
|
||||
|
||||
GRAPHICS::BEGIN_SCALEFORM_MOVIE_METHOD(scaleform, "SET_FOCUS");
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(1); // VISIBLE_STATE_DEFAULT
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0); // scopeType (unused)
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0); // scope (unused)
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME_STRING(player_name); // player
|
||||
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT((int)HudColor::HUD_COLOUR_PURE_WHITE); // eHudColour
|
||||
GRAPHICS::END_SCALEFORM_MOVIE_METHOD();
|
||||
|
||||
GRAPHICS::DRAW_SCALEFORM_MOVIE_FULLSCREEN(scaleform, 255, 255, 255, 255, 0);
|
||||
|
||||
// fix broken scaleforms, when chat alrdy opened
|
||||
if (const auto chat_data = *g_pointers->m_gta.m_chat_data; chat_data && (chat_data->m_chat_open || chat_data->m_timer_two))
|
||||
HUD::CLOSE_MP_TEXT_CHAT();
|
||||
}
|
||||
|
||||
inline void crash_blocked(CNetGamePlayer* player, const char* crash)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
if ((g_player_service->get_by_id(player->m_player_id)->is_friend() && g.session.trust_friends)
|
||||
|| g_player_service->get_by_id(player->m_player_id)->is_trusted
|
||||
|| g.session.trust_session)
|
||||
return;
|
||||
|
||||
if (g.reactions.crash.notify)
|
||||
g_notification_service->push_error("Protections", std::format("Blocked {} crash from {}", crash, player->get_name()));
|
||||
|
||||
if (g.reactions.crash.log)
|
||||
LOG(WARNING) << "Blocked " << crash << " crash from " << player->get_name() << " ("
|
||||
<< (player->get_net_data() ? player->get_net_data()->m_gamer_handle.m_rockstar_id : 0) << ")";
|
||||
|
||||
if (g.reactions.crash.announce_in_chat)
|
||||
{
|
||||
g_fiber_pool->queue_job([player, crash] {
|
||||
auto chat = std::vformat("NOTIFICATION_CRASH_TYPE_BLOCKED"_T, std::make_format_args(player->get_name(), crash));
|
||||
chat = std::format("{} {}", g.session.chat_output_prefix, chat);
|
||||
|
||||
if (g_hooking->get_original<hooks::send_chat_message>()(*g_pointers->m_gta.m_send_chat_ptr,
|
||||
g_player_service->get_self()->get_net_data(),
|
||||
chat.data(),
|
||||
g.reactions.crash.is_team_only))
|
||||
draw_chat(chat.c_str(), g_player_service->get_self()->get_name(), g.reactions.crash.is_team_only);
|
||||
});
|
||||
}
|
||||
|
||||
g.reactions.crash.process_common(g_player_service->get_by_id(player->m_player_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.reactions.crash.notify)
|
||||
g_notification_service->push_error("Protections", std::format("Blocked {} crash from unknown player", crash));
|
||||
}
|
||||
}
|
||||
void crash_blocked(CNetGamePlayer* player, const char* crash);
|
||||
|
||||
// Shows a busy spinner till the value at the address equals the value passed or if timeout is hit
|
||||
inline void busy_spinner(std::string_view text, int* address, int value, int timeout = 15)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_BUSYSPINNER_ON("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_BUSYSPINNER_ON(3);
|
||||
void busy_spinner(std::string_view text, int* address, int value, int timeout = 15);
|
||||
|
||||
for (size_t i = 0; *address != value && i < (size_t)timeout * 100; i++)
|
||||
script::get_current()->yield(10ms);
|
||||
void show_subtitle(std::string_view text, int ms = 2000);
|
||||
|
||||
HUD::BUSYSPINNER_OFF();
|
||||
}
|
||||
void display_help_text(std::string_view text);
|
||||
|
||||
inline void show_subtitle(std::string_view text, int ms = 2000)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_PRINT("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_PRINT(ms, 1);
|
||||
}
|
||||
|
||||
inline void display_help_text(std::string_view text)
|
||||
{
|
||||
HUD::BEGIN_TEXT_COMMAND_DISPLAY_HELP("STRING");
|
||||
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(text.data());
|
||||
HUD::END_TEXT_COMMAND_DISPLAY_HELP(0, 0, 1, -1);
|
||||
}
|
||||
|
||||
inline void player_joined(CNetGamePlayer* net_game_player)
|
||||
{
|
||||
above_map(std::format("<C>{}</C> joined.", net_game_player->get_name()));
|
||||
}
|
||||
|
||||
}
|
||||
void player_joined(CNetGamePlayer* net_game_player);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace big::protection
|
||||
{
|
||||
constexpr auto crash_objects = {"prop_dummy_01"_J, "prop_dummy_car"_J, "prop_dummy_light"_J, "prop_dummy_plane"_J, "prop_distantcar_night"_J, "prop_distantcar_day"_J, "hei_bh1_08_details4_em_night"_J, "dt1_18_sq_night_slod"_J, "ss1_12_night_slod"_J, "hash_b334b5e2_qyquzxq_collision"_J, "h4_prop_bush_bgnvla_med_01"_J, "h4_prop_bush_bgnvla_lrg_01"_J, "h4_prop_bush_buddleia_low_01"_J, "h4_prop_bush_ear_aa"_J, "h4_prop_bush_ear_ab"_J, "h4_prop_bush_fern_low_01"_J, "h4_prop_bush_fern_tall_cc"_J, "h4_prop_bush_mang_ad"_J, "h4_prop_bush_mang_low_aa"_J, "h4_prop_bush_mang_low_ab"_J, "h4_prop_bush_seagrape_low_01"_J, "prop_h4_ground_cover"_J, "h4_prop_weed_groundcover_01"_J, "h4_prop_grass_med_01"_J, "h4_prop_grass_tropical_lush_01"_J, "h4_prop_grass_wiregrass_01"_J, "h4_prop_weed_01_plant"_J, "h4_prop_weed_01_row"_J, "urbanweeds02_l1"_J, "proc_forest_grass01"_J, "prop_small_bushyba"_J, "v_res_d_dildo_a"_J, "v_res_d_dildo_b"_J, "v_res_d_dildo_c"_J, "v_res_d_dildo_d"_J, "v_res_d_dildo_e"_J, "v_res_d_dildo_f"_J, "v_res_skateboard"_J, "prop_battery_01"_J, "prop_barbell_01"_J, "prop_barbell_02"_J, "prop_bandsaw_01"_J, "prop_bbq_3"_J, "v_med_curtainsnewcloth2"_J, "bh1_07_flagpoles"_J, "hash_058a7eb5_deihiws_collision"_J, "proc_dry_plants_01"_J, "proc_leafyplant_01"_J, "proc_grassplantmix_02"_J, "proc_dryplantsgrass_01"_J, "proc_dryplantsgrass_02"_J, "proc_dryplantsgrass_02"_J, "proc_grasses01"_J, "prop_dryweed_002_a"_J, "prop_fernba"_J, "prop_weed_001_aa"_J, "urbangrnfrnds_01"_J, "urbanweeds01"_J, "prop_dandy_b"_J, "v_proc2_temp"_J, "prop_fernbb"_J, "proc_drygrassfronds01"_J, "prop_log_ae"_J, "prop_grass_da"_J, "prop_fragtest_cnst_04"_J};
|
||||
constexpr auto crash_objects = {"prop_facgate_05_r_dam_l1"_J, "v_61_lng_mesh_unita_swap"_J, "prop_crt_mon_02"_J, "xs_prop_arena_pit_fire_01a_wl"_J, "prop_billboard_07"_J, "prop_recyclebin_02_d"_J, "prop_billboard_14"_J, "v_res_fa_book02"_J, "sf_int1_dropdownlight041"_J, "w_sg_pumpshotgunmk2_camo6"_J, "ch_prop_cash_low_trolly_01b"_J, "prop_ld_headset_01"_J, "sf_int1_office_wpaper_6"_J, "v_74_it3_ceiling_smoke_01_skin"_J, "prop_sh_tt_fridgedoor"_J, "ch_prop_arcade_race_02a"_J, "v_61_kit_over_dec_cruma"_J, "gr_prop_gr_rsply_crate01a"_J, "prop_snow_streetlight_01_frag_"_J, "v_34_sm_proc"_J, "tr_int1_lightcap_proxy001"_J, "v_ilev_tort_door"_J, "ch_prop_arcade_street_01b"_J, "prop_ic_repair_p"_J, "sf_int2_elevator_details_02"_J, "prop_cs4_05_tdoor"_J, "vfx_it1_02"_J, "cloudhat_wispy_b"_J, "hei_p_pre_heist_trash"_J, "v_ilev_trev_patiodoor"_J, "prop_bin_10a"_J, "sm_prop_offchair_smug_01"_J, "stt_prop_stunt_tube_fn_02"_J, "m23_2_prop_m32_hat_captain_01a"_J, "vw_prop_vw_arcade_04d_screen"_J, "prop_food_juice02"_J, "m23_2_prop_m32_mazebankcard_01a"_J, "v_28_alrm_case011"_J, "apa_mp_h_acc_pot_pouri_01"_J, "xm3_prop_xm3_crate_ammo_01a"_J, "prop_blackjack_01"_J, "prop_cs_mini_tv"_J, "v_res_fa_basket"_J, "prop_plant_int_02b"_J, "prop_umpire_01"_J, "gr_prop_gr_fnclink_03g"_J, "prop_rub_tyre_dam3"_J, "ba_prop_battle_lights_support"_J, "prop_fnclink_09a"_J, "ba_prop_battle_dj_mixer_01e"_J, "ar_prop_ar_neon_gate8x_04a"_J, "xs_propintarena_structure_f_03b"_J, "des_plog_door_end"_J, "v_ret_fh_chair01"_J, "gr_prop_gr_offchair_01a"_J, "hei_p_pre_heist_coke"_J, "cloudhat_puff_b"_J, "v_ind_cfbucket"_J, "p_hw1_22_doors_s"_J, "arbitergt"_J, "slod_human"_J, "prop_dummy_01"_J, "prop_dummy_car"_J, "prop_dummy_light"_J, "prop_dummy_plane"_J, "prop_distantcar_night"_J, "prop_distantcar_day"_J, "hei_bh1_08_details4_em_night"_J, "dt1_18_sq_night_slod"_J, "ss1_12_night_slod"_J, "hash_b334b5e2_qyquzxq_collision"_J, "h4_prop_bush_bgnvla_med_01"_J, "h4_prop_bush_bgnvla_lrg_01"_J, "h4_prop_bush_buddleia_low_01"_J, "h4_prop_bush_ear_aa"_J, "h4_prop_bush_ear_ab"_J, "h4_prop_bush_fern_low_01"_J, "h4_prop_bush_fern_tall_cc"_J, "h4_prop_bush_mang_ad"_J, "h4_prop_bush_mang_low_aa"_J, "h4_prop_bush_mang_low_ab"_J, "h4_prop_bush_seagrape_low_01"_J, "prop_h4_ground_cover"_J, "h4_prop_weed_groundcover_01"_J, "h4_prop_grass_med_01"_J, "h4_prop_grass_tropical_lush_01"_J, "h4_prop_grass_wiregrass_01"_J, "h4_prop_weed_01_plant"_J, "h4_prop_weed_01_row"_J, "urbanweeds02_l1"_J, "proc_forest_grass01"_J, "prop_small_bushyba"_J, "v_res_d_dildo_a"_J, "v_res_d_dildo_b"_J, "v_res_d_dildo_c"_J, "v_res_d_dildo_d"_J, "v_res_d_dildo_e"_J, "v_res_d_dildo_f"_J, "v_res_skateboard"_J, "prop_battery_01"_J, "prop_barbell_01"_J, "prop_barbell_02"_J, "prop_bandsaw_01"_J, "prop_bbq_3"_J, "v_med_curtainsnewcloth2"_J, "bh1_07_flagpoles"_J, "hash_058a7eb5_deihiws_collision"_J, "proc_dry_plants_01"_J, "proc_leafyplant_01"_J, "proc_grassplantmix_02"_J, "proc_dryplantsgrass_01"_J, "proc_dryplantsgrass_02"_J, "proc_dryplantsgrass_02"_J, "proc_grasses01"_J, "prop_dryweed_002_a"_J, "prop_fernba"_J, "prop_weed_001_aa"_J, "urbangrnfrnds_01"_J, "urbanweeds01"_J, "prop_dandy_b"_J, "v_proc2_temp"_J, "prop_fernbb"_J, "proc_drygrassfronds01"_J, "prop_log_ae"_J, "prop_grass_da"_J, "prop_fragtest_cnst_04"_J};
|
||||
bool is_crash_object(rage::joaat_t model)
|
||||
{
|
||||
if (!model_info::get_model(model))
|
||||
|
@ -120,7 +120,7 @@ namespace big::scripts
|
||||
if (!force_host("am_launcher"_J))
|
||||
{
|
||||
// 2F) Failed to force host of launcher
|
||||
g_notification_service->push_error("Script", "Cannot force script host of am_launcher");
|
||||
g_notification_service.push_error("Script", "Cannot force script host of am_launcher");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ namespace big::scripts
|
||||
else
|
||||
{
|
||||
// 1F) Cannot find launcher
|
||||
g_notification_service->push_error("Script", "Cannot start script, am_launcher not running locally");
|
||||
g_notification_service.push_error("Script", "Cannot start script, am_launcher not running locally");
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,13 +216,13 @@ namespace big::scripts
|
||||
|
||||
if (g.m_mission_creator_thread || SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("creator"_J) != 0 || SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) != 0 || STREAMING::IS_PLAYER_SWITCH_IN_PROGRESS() || CUTSCENE::IS_CUTSCENE_ACTIVE())
|
||||
{
|
||||
g_notification_service->push_warning("Creator", "Cannot start creator now");
|
||||
g_notification_service.push_warning("Creator", "Cannot start creator now");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MISC::GET_NUMBER_OF_FREE_STACKS_OF_THIS_SIZE(60500) == 0)
|
||||
{
|
||||
g_notification_service->push_warning("Creator", "No free stacks for MISSION stack size");
|
||||
g_notification_service.push_warning("Creator", "No free stacks for MISSION stack size");
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,16 +24,6 @@
|
||||
|
||||
namespace big::session
|
||||
{
|
||||
static void gamer_handle_serialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
||||
{
|
||||
buf.Write<uint8_t>(*reinterpret_cast<uint8_t*>(&hnd.m_platform), 8);
|
||||
if (*reinterpret_cast<uint8_t*>(&hnd.m_platform) == 3)
|
||||
{
|
||||
buf.WriteInt64(*(int64_t*)&hnd.m_rockstar_id, 64);
|
||||
buf.Write<uint8_t>(*reinterpret_cast<uint8_t*>(reinterpret_cast<__int64>(&hnd) + 9), 8);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool join_type(eSessionType session)
|
||||
{
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH("pausemenu_multiplayer"_J);
|
||||
@ -100,7 +90,7 @@ namespace big::session
|
||||
{
|
||||
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) != 0 || STREAMING::IS_PLAYER_SWITCH_IN_PROGRESS())
|
||||
{
|
||||
g_notification_service->push_error("RID Joiner", "Player switch in progress, wait a bit.");
|
||||
g_notification_service.push_error("RID Joiner", "Player switch in progress, wait a bit.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -110,7 +100,7 @@ namespace big::session
|
||||
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) == 0)
|
||||
{
|
||||
g.session.join_queued = false;
|
||||
g_notification_service->push_error("RID Joiner", "Unable to launch maintransition");
|
||||
g_notification_service.push_error("RID Joiner", "Unable to launch maintransition");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -119,7 +109,7 @@ namespace big::session
|
||||
{
|
||||
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) != 0 || STREAMING::IS_PLAYER_SWITCH_IN_PROGRESS())
|
||||
{
|
||||
g_notification_service->push_error("RID Joiner", "Player switch in progress, wait a bit.");
|
||||
g_notification_service.push_error("RID Joiner", "Player switch in progress, wait a bit.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,7 +130,7 @@ namespace big::session
|
||||
}
|
||||
}
|
||||
|
||||
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
||||
g_notification_service.push_error("RID Joiner", "Target player is offline?");
|
||||
}
|
||||
|
||||
inline void join_by_username(std::string username)
|
||||
@ -154,7 +144,7 @@ namespace big::session
|
||||
});
|
||||
return;
|
||||
}
|
||||
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
||||
g_notification_service.push_error("RID Joiner", "Target player is offline?");
|
||||
});
|
||||
}
|
||||
|
||||
@ -165,9 +155,9 @@ namespace big::session
|
||||
bool success = g_pointers->m_gta.m_invite_player_by_gamer_handle(g_pointers->m_gta.m_network_config, &player_handle, 1, 0, 0, 0);
|
||||
|
||||
if (!success)
|
||||
return g_notification_service->push_error("Network", "Target player could not be invited, they might be offline?");
|
||||
return g_notification_service.push_error("Network", "Target player could not be invited, they might be offline?");
|
||||
|
||||
g_notification_service->push_success("Network", "Target player has been invited to your session!");
|
||||
g_notification_service.push_success("Network", "Target player has been invited to your session!");
|
||||
}
|
||||
|
||||
inline void show_profile_by_rockstar_id(uint64_t rid)
|
||||
|
@ -1,128 +0,0 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "core/enums.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
static const char* spam_texts[] = {
|
||||
"qq", //a chinese chat app
|
||||
"QQ",
|
||||
"WWW.",
|
||||
"www.",
|
||||
".cn",
|
||||
".CN",
|
||||
".cc",
|
||||
".CC",
|
||||
".TOP",
|
||||
".COM",
|
||||
".top",
|
||||
"\xE3\x80\x90", //left bracket in Chinese input method
|
||||
"/Menu",
|
||||
"Money/",
|
||||
"Money\\\\",
|
||||
"Money\\",
|
||||
".gg",
|
||||
"--->",
|
||||
"shopgta5",
|
||||
"doit#",
|
||||
"krutka#",
|
||||
"<b>",
|
||||
"P888",
|
||||
"gtacash",
|
||||
"\xE6\x89\xA3\xE6\x89\xA3", // no clue what this is
|
||||
"\xE5\xBE\xAE\xE4\xBF\xA1", // "wechat" in Chinese
|
||||
".cc",
|
||||
"<font s",
|
||||
"sellix.io",
|
||||
"ezcars",
|
||||
"PLANO INICIAL", // "initial plan"
|
||||
"REP +",
|
||||
"20R$", // Brazil currency?
|
||||
"l55.me",
|
||||
"\xE5\xBA\x97", //"shop" in Chinese
|
||||
"\xE9\x92\xB1", //"money" in Chinese
|
||||
"\xE5\x88\xB7", //"make(money)" in Chinese
|
||||
"\xE8\x90\x9D\xE8\x8E\x89", // "cute girl" in Chinese
|
||||
"\xE5\xA6\x88", // "mother" in Chinese
|
||||
"\xE7\xBE\x8E\xE5\xA5\xB3", // "sexy girl" in Chinese
|
||||
"\xE5\xBC\xBA\xE5\xA5\xB8", // "rape" in Chinese
|
||||
"\xE8\x90\x9D", // "loli" in Chinese
|
||||
"\xE6\x8C\x82", // "hack" in Chinese
|
||||
"\xE5\x85\x83", // chinese dollar
|
||||
"\xE9\x98\xB4\xE4\xBC\xA0\xE5\xAA\x92", // "Yin Media" in Chinese
|
||||
"\xE7\xBD\x91\xE7\xBA\xA2", // "internet celebrities" in Chinese
|
||||
"TRUSTPILOT",
|
||||
"cashlounge",
|
||||
"Fast Delivery",
|
||||
"yosativa",
|
||||
"rich2day",
|
||||
"LevelLifters",
|
||||
". com",
|
||||
"$1,000,000,000",
|
||||
"Instant Delivery",
|
||||
"0 Ban Risk",
|
||||
"Discord For Cheap Money",
|
||||
"10-30m",
|
||||
"Discord todo",
|
||||
};
|
||||
}
|
||||
|
||||
namespace big::spam
|
||||
{
|
||||
inline SpamReason is_text_spam(const char* text, player_ptr player)
|
||||
{
|
||||
if (g.session.use_spam_timer)
|
||||
{
|
||||
if (player->last_message_time.has_value())
|
||||
{
|
||||
auto currentTime = std::chrono::steady_clock::now();
|
||||
auto diff = std::chrono::duration_cast<std::chrono::seconds>(currentTime - player->last_message_time.value());
|
||||
player->last_message_time.emplace(currentTime);
|
||||
|
||||
if (strlen(text) > g.session.spam_length && diff.count() <= g.session.spam_timer)
|
||||
return SpamReason::TIMER_DETECTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->last_message_time.emplace(std::chrono::steady_clock::now());
|
||||
}
|
||||
}
|
||||
for (auto e : spam_texts)
|
||||
if (strstr(text, e) != 0)
|
||||
return SpamReason::STATIC_DETECTION;
|
||||
|
||||
return SpamReason::NOT_A_SPAMMER;
|
||||
}
|
||||
|
||||
inline void log_chat(char* msg, player_ptr player, SpamReason spam_reason, bool is_team)
|
||||
{
|
||||
std::ofstream log(g_file_manager.get_project_file(spam_reason != SpamReason::NOT_A_SPAMMER ? "./spam.log" : "./chat.log").get_path(), std::ios::app);
|
||||
|
||||
auto& data = *player->get_net_data();
|
||||
auto ip = player->get_ip_address();
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
|
||||
auto timer = std::chrono::system_clock::to_time_t(now);
|
||||
auto local_time = *std::localtime(&timer);
|
||||
|
||||
std::string spam_reason_str = "";
|
||||
|
||||
switch (spam_reason)
|
||||
{
|
||||
case SpamReason::STATIC_DETECTION: spam_reason_str = "(Static Detection) "; break;
|
||||
case SpamReason::TIMER_DETECTION: spam_reason_str = "(Timer Detection) "; break;
|
||||
}
|
||||
|
||||
log << spam_reason_str << "[" << std::put_time(&local_time, "%m/%d/%Y %I:%M:%S") << ":" << std::setfill('0') << std::setw(3) << ms.count() << " " << std::put_time(&local_time, "%p") << "] ";
|
||||
|
||||
if (ip)
|
||||
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <" << (int)ip.value().m_field1 << "."
|
||||
<< (int)ip.value().m_field2 << "." << (int)ip.value().m_field3 << "." << (int)ip.value().m_field4 << "> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
|
||||
else
|
||||
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <UNKNOWN> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
|
||||
|
||||
log.close();
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ namespace big::teleport
|
||||
|
||||
if (ENTITY::IS_ENTITY_DEAD(ent, true))
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_PLAYER_IS_DEAD"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_PLAYER_IS_DEAD"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ namespace big::teleport
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_FAILED_TO_TAKE_CONTROL"_T.data());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -131,7 +131,7 @@ namespace big::teleport
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh))
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_INVALID_VEHICLE"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_INVALID_VEHICLE"_T.data());
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace big::teleport
|
||||
|
||||
if (seat_index == 255)
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_NO_SEATS_FREE"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_NO_SEATS_FREE"_T.data());
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -196,7 +196,7 @@ namespace big::teleport
|
||||
{
|
||||
if (!to_blip((int)BlipIcons::Waypoint))
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_NO_WAYPOINT_SET"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_NO_WAYPOINT_SET"_T.data());
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -209,7 +209,7 @@ namespace big::teleport
|
||||
|
||||
if (!blip::get_objective_location(location))
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_NO_OBJECTIVE"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_NO_OBJECTIVE"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -222,14 +222,14 @@ namespace big::teleport
|
||||
{
|
||||
if (!*g_pointers->m_gta.m_is_session_started)
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_NOT_ONLINE"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_NOT_ONLINE"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto blip = blip::get_selected_blip();
|
||||
if (blip == nullptr)
|
||||
{
|
||||
g_notification_service->push_warning("TELEPORT"_T.data(), "TELEPORT_NOTHING_SELECTED"_T.data());
|
||||
g_notification_service.push_warning("TELEPORT"_T.data(), "TELEPORT_NOTHING_SELECTED"_T.data());
|
||||
return false;
|
||||
}
|
||||
Entity entity = self::ped;
|
||||
|
@ -55,13 +55,13 @@ namespace big::toxic
|
||||
{
|
||||
if (!g_player_service->get_self()->is_host())
|
||||
{
|
||||
g_notification_service->push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_HOST_REQUIRED"_T.data());
|
||||
g_notification_service.push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_HOST_REQUIRED"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target->player_time_value.has_value())
|
||||
{
|
||||
g_notification_service->push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_NO_PLAYER_TIMESTAMP"_T.data());
|
||||
g_notification_service.push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_NO_PLAYER_TIMESTAMP"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ namespace big::toxic
|
||||
{
|
||||
if (!target->player_time_value.has_value())
|
||||
{
|
||||
g_notification_service->push_error("WARP_TIME_TITLE"_T.data(), "MODIFY_TIME_NO_PLAYER_TIMESTAMP"_T.data());
|
||||
g_notification_service.push_error("WARP_TIME_TITLE"_T.data(), "MODIFY_TIME_NO_PLAYER_TIMESTAMP"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ namespace big::toxic
|
||||
{
|
||||
if (!g_player_service->get_self()->is_host())
|
||||
{
|
||||
g_notification_service->push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_HOST_REQUIRED"_T.data());
|
||||
g_notification_service.push_error("MODIFY_TIME"_T.data(), "MODIFY_TIME_HOST_REQUIRED"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -167,4 +167,4 @@ namespace big::toxic
|
||||
{
|
||||
set_time_all((*g_pointers->m_gta.m_network_time)->m_time + millis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ namespace big::train
|
||||
TASK::CLEAR_PED_TASKS_IMMEDIATELY(ped);
|
||||
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), train, -1);
|
||||
g_notification_service->push_success("HIJACK_TRAIN"_T.data(), "HIJACK_TRAIN_FOUND_TRAIN"_T.data());
|
||||
g_notification_service.push_success("HIJACK_TRAIN"_T.data(), "HIJACK_TRAIN_FOUND_TRAIN"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("HIJACK_TRAIN"_T.data(), "Cannot find any trains nearby");
|
||||
g_notification_service.push_warning("HIJACK_TRAIN"_T.data(), "Cannot find any trains nearby");
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ namespace big::train
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_warning("HIJACK_TRAIN"_T.data(), "Cannot find any trains nearby");
|
||||
g_notification_service.push_warning("HIJACK_TRAIN"_T.data(), "Cannot find any trains nearby");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,13 +56,13 @@ namespace big::vehicle
|
||||
void bring(Vehicle veh, Vector3 location, bool put_in, int seatIdx)
|
||||
{
|
||||
if (!ENTITY::IS_ENTITY_A_VEHICLE(veh))
|
||||
return g_notification_service->push_error("VEHICLE"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
return g_notification_service.push_error("VEHICLE"_T.data(), "VEHICLE_INVALID"_T.data());
|
||||
|
||||
auto vecVehicleLocation = ENTITY::GET_ENTITY_COORDS(veh, true);
|
||||
entity::load_ground_at_3dcoord(vecVehicleLocation);
|
||||
|
||||
if (!entity::take_control_of(veh))
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
return g_notification_service.push_warning("VEHICLE"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
auto ped = self::ped;
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0);
|
||||
@ -354,9 +354,9 @@ namespace big::vehicle
|
||||
}
|
||||
|
||||
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked)
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked, bool is_script_vehicle)
|
||||
{
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked);
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked, is_script_vehicle);
|
||||
if (vehicle == 0)
|
||||
{
|
||||
return 0;
|
||||
@ -371,12 +371,12 @@ namespace big::vehicle
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
||||
script::get_current()->yield(10ms);
|
||||
//script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle, owned_mods[MOD_PLATE_STYLE]);
|
||||
VEHICLE::SET_VEHICLE_WINDOW_TINT(vehicle, owned_mods[MOD_WINDOW_TINT]);
|
||||
VEHICLE::SET_VEHICLE_WHEEL_TYPE(vehicle, owned_mods[MOD_WHEEL_TYPE]);
|
||||
script::get_current()->yield(10ms);
|
||||
//script::get_current()->yield(10ms);
|
||||
|
||||
VEHICLE::SET_VEHICLE_COLOURS(vehicle, owned_mods[MOD_PRIMARY_COL], owned_mods[MOD_SECONDARY_COL]);
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOURS(vehicle, owned_mods[MOD_PEARLESCENT_COL], owned_mods[MOD_WHEEL_COL]);
|
||||
@ -605,7 +605,7 @@ namespace big::vehicle
|
||||
if (current_vehicle)
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(current_vehicle, state, immediately, disable_auto_start);
|
||||
else
|
||||
return g_notification_service->push_warning("VEHICLE"_T.data(), "PLEASE_ENTER_VEHICLE"_T.data());
|
||||
return g_notification_service.push_warning("VEHICLE"_T.data(), "PLEASE_ENTER_VEHICLE"_T.data());
|
||||
}
|
||||
|
||||
void downgrade(Vehicle vehicle)
|
||||
@ -621,7 +621,7 @@ namespace big::vehicle
|
||||
{
|
||||
if (!entity::take_control_of(veh, 4000))
|
||||
{
|
||||
g_notification_service->push_warning("REMOTE_CONTROL"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
g_notification_service.push_warning("REMOTE_CONTROL"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace big::vehicle
|
||||
Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked = true, bool script_veh = false);
|
||||
Vehicle clone_from_vehicle_data(std::map<int, int32_t>& data, Vector3 location, float heading);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle_idx(script_global vehicle_idx);
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true);
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true, bool is_script_vehicle = false);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle(Vehicle vehicle);
|
||||
void teleport_into_vehicle(Vehicle veh);
|
||||
void max_vehicle(Vehicle veh);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user