Add Return Value Support for Script Functions (#3479)
* Add Return Value Support for Script Functions * Removed address-of operator on instruction_pointer parameter, as sol is pass-by-value. * Fixed reset_session_data & start_creator_script * Added support for Vector3 and updated casting for bool type for proper conversion to Lua boolean * Updated documentation for scr_function * Added get_int method and updated param names for script functions * Fix #3497 graceful landing not saved. * Added a check in view_lsc to see if the vehicle can accept clan logos first. * Fixed vehicle clan logo SP bypass not working properly. * Fixed COPY VEHICLE not giving persist_car_service::spawn_vehicle_json the target's ped so it can copy their clan logo and not ours. Fixed spawn_vehicle_json calling add_clan_logo_to_vehicle with our logo and not the ped parameter's logo. * Added Clone Player Car. * Fixed has_clan_logo check in view_lsc being given the wrong parameter. --------- Co-authored-by: gir489 <100792176+gir489returns@users.noreply.github.com>
This commit is contained in:
parent
013b463536
commit
09b91ca6d7
@ -63,6 +63,18 @@ Rips the current memory address and returns a new pointer object.
|
||||
pointer = pointer:rip(offset)
|
||||
```
|
||||
|
||||
### `get_int()`
|
||||
|
||||
Retrieves the value stored at the memory address as the specified type.
|
||||
|
||||
- **Returns:**
|
||||
- `number`: the value stored at the memory address as the specified type.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
number = pointer:get_int()
|
||||
```
|
||||
|
||||
### `get_byte()`
|
||||
|
||||
Retrieves the value stored at the memory address as the specified type.
|
||||
@ -123,6 +135,18 @@ Retrieves the value stored at the memory address as the specified type.
|
||||
number = pointer:get_qword()
|
||||
```
|
||||
|
||||
### `set_int(value)`
|
||||
|
||||
Sets the value at the memory address to the specified value of the given type.
|
||||
|
||||
- **Parameters:**
|
||||
- `value` (number): new value.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
pointer:set_int(value)
|
||||
```
|
||||
|
||||
### `set_byte(value)`
|
||||
|
||||
Sets the value at the memory address to the specified value of the given type.
|
||||
|
43
docs/lua/tables/scr_function.md
Normal file
43
docs/lua/tables/scr_function.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Table: scr_function
|
||||
|
||||
Table for calling GTA script functions. Needs to be called in the fiber pool or a GTA script. Only call the function when necessary.
|
||||
|
||||
## Functions (2)
|
||||
|
||||
### `call_script_function(script_name, function_name, pattern, return_type_string, args_)`
|
||||
|
||||
Calls a script function with the given arguments. Returns the return value as the given type.
|
||||
|
||||
- **Parameters:**
|
||||
- `script_name` (string): Name of the script.
|
||||
- `function_name` (string): Name of the function. This parameter needs to be unique.
|
||||
- `pattern` (string): Pattern to scan for within the script.
|
||||
- `return_type_string` (string): Return type of the function. Supported types are **"int"**, **"bool"**, **"const char\*/string"**, **"ptr/pointer/*"**, **"float"**, and **"vector3"**. Anything different will be rejected.
|
||||
- `_args` (table): Arguments to pass to the function. Supported types are the same as return types.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
local value = scr_function.call_script_function("freemode", "wear_sunglasses_at_night", "69 42 06 66", "bool", {
|
||||
{ "int", 69 },
|
||||
{ "float", 4.20 },
|
||||
{ "int", 666 }
|
||||
})
|
||||
```
|
||||
|
||||
### `call_script_function(script_name, instruction_pointer, return_type_string, args_)`
|
||||
|
||||
Calls a script function directly using the function position with the given arguments. Returns the return value as the given type.
|
||||
|
||||
- **Parameters:**
|
||||
- `script_name` (string): Name of the script.
|
||||
- `function_name` (string): Name of the function.
|
||||
- `instruction_pointer` (integer): Position of the function within the script.
|
||||
- `return_type_string` (string): Return type of the function. Supported types are **"int"**, **"bool"**, **"const char\*/string"**, **"ptr/pointer/*"**, **"float"**, and **"vector3"**. Anything different will be rejected.
|
||||
- `_args` (table): Arguments to pass to the function. Supported types are the same as return types.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
local value = scr_function.call_script_function("freemode", 0xE792, "string", {
|
||||
{ "int", 191 }
|
||||
})
|
||||
```
|
@ -106,22 +106,6 @@ Adds a patch for the specified script.
|
||||
script.add_patch("fm_content_xmas_truck", "Flickering Fix", "56 ? ? 4F ? ? 40 ? 5D ? ? ? 74", 0, {0x2B, 0x00, 0x00})
|
||||
```
|
||||
|
||||
### `call_function(name, script_name, pattern, offset, _args)`
|
||||
|
||||
Calls a function from the specified script.
|
||||
|
||||
- **Parameters:**
|
||||
- `name` (string): The name of the script function.
|
||||
- `script_name` (string): The name of the script.
|
||||
- `pattern` (string): The pattern to scan for within the script.
|
||||
- `offset` (integer): The position within the pattern.
|
||||
- `_args` (table): The arguments to pass to the script function.
|
||||
|
||||
**Example Usage:**
|
||||
```lua
|
||||
script.call_function("Collect Collectible", "freemode", "2D 05 33 00 00", 0, {17, 0, 1, 1, 0})
|
||||
```
|
||||
|
||||
### `start_launcher_script(script_name)`
|
||||
|
||||
Tries to start a launcher script. Needs to be called in the fiber pool or a loop.
|
||||
|
@ -54,7 +54,6 @@ namespace big
|
||||
{
|
||||
looped::self_wanted();
|
||||
looped::self_hud();
|
||||
looped::self_dance_mode();
|
||||
looped::self_persist_outfit();
|
||||
|
||||
script::get_current()->yield();
|
||||
@ -149,21 +148,9 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
void backend::lscustoms_loop()
|
||||
{
|
||||
LOG(INFO) << "Starting script: Ls customs";
|
||||
|
||||
while (g_running)
|
||||
{
|
||||
looped::vehicle_ls_customs();
|
||||
|
||||
script::get_current()->yield();
|
||||
}
|
||||
}
|
||||
|
||||
void backend::rainbowpaint_loop()
|
||||
{
|
||||
LOG(INFO) << "Starting script: Rainbow paint";
|
||||
LOG(INFO) << "Starting script: Rainbow Paint";
|
||||
|
||||
while (g_running)
|
||||
{
|
||||
|
@ -13,7 +13,6 @@ namespace big
|
||||
static void vehicles_loop();
|
||||
static void misc_loop();
|
||||
static void remote_loop();
|
||||
static void lscustoms_loop();
|
||||
static void rainbowpaint_loop();
|
||||
static void disable_control_action_loop();
|
||||
static void world_loop();
|
||||
|
@ -9,7 +9,7 @@ namespace big
|
||||
|
||||
virtual void execute(player_ptr player, const command_arguments& _args, const std::shared_ptr<command_context> ctx) override
|
||||
{
|
||||
scr_functions::join_ceo({player->id(), 0, false, false});
|
||||
scr_functions::set_as_ceo.call<void>(player->id(), 0, false, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
29
src/backend/commands/player/vehicle/clone_player_car.cpp
Normal file
29
src/backend/commands/player/vehicle/clone_player_car.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include "backend/player_command.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "services/vehicle/persist_car_service.hpp"
|
||||
#include "util/entity.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class clone_player_car : player_command
|
||||
{
|
||||
using player_command::player_command;
|
||||
|
||||
virtual void execute(player_ptr player, const command_arguments& _args, const std::shared_ptr<command_context> ctx) override
|
||||
{
|
||||
Player player_id = player->id();
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
Vehicle v = persist_car_service::clone_ped_car(ped, PED::GET_VEHICLE_PED_IS_USING(ped));
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), v, -1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
clone_player_car g_clone_player_car("cloneplayercar", "SPAWN_CLONE", "", 0);
|
||||
}
|
@ -27,7 +27,6 @@ namespace big
|
||||
|
||||
static void self_wanted();
|
||||
static void self_hud();
|
||||
static void self_dance_mode();
|
||||
static void self_persist_outfit();
|
||||
|
||||
static void session_pop_multiplier_areas();
|
||||
@ -48,7 +47,6 @@ namespace big
|
||||
static void vehicle_auto_drive();
|
||||
static void vehicle_allow_all_weapons();
|
||||
static void vehicle_boost_behavior();
|
||||
static void vehicle_ls_customs();
|
||||
static void vehicle_rainbow_paint();
|
||||
|
||||
static void weapons_tp_gun();
|
||||
|
@ -1,63 +0,0 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool bLastDanceMode = false;
|
||||
void looped::self_dance_mode()
|
||||
{
|
||||
if (g.self.dance_mode && SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) > 0)
|
||||
g.self.dance_mode = false;
|
||||
|
||||
if (g.self.dance_mode && g.self.dance_mode != bLastDanceMode)
|
||||
{
|
||||
g_script_patcher_service->update();
|
||||
scripts::request_script("am_mp_nightclub"_J);
|
||||
if (!scripts::wait_till_loaded("am_mp_nightclub"_J))
|
||||
return;
|
||||
|
||||
auto thread = SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH("am_mp_nightclub"_J, 19400 /*PROPERTY_INT*/);
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("am_mp_nightclub"_J);
|
||||
|
||||
if (!thread)
|
||||
return;
|
||||
|
||||
g.m_dance_thread = gta_util::find_script_thread_by_id(thread);
|
||||
g.m_dance_program = gta_util::find_script_program("am_mp_nightclub"_J);
|
||||
|
||||
g.m_dance_thread->m_context.m_state = rage::eThreadState::unk_3;
|
||||
|
||||
// perform initial setup
|
||||
gta_util::execute_as_script(g.m_dance_thread, [] {
|
||||
NETWORK::NETWORK_SET_THIS_SCRIPT_IS_NETWORK_SCRIPT(32, true, 32);
|
||||
scr_functions::init_nightclub_script({});
|
||||
});
|
||||
|
||||
scr_functions::dance_loop.populate_ip();
|
||||
bLastDanceMode = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g.self.dance_mode && g.self.dance_mode != bLastDanceMode)
|
||||
{
|
||||
if (g.m_dance_thread)
|
||||
g.m_dance_thread->kill();
|
||||
|
||||
g.m_dance_thread = nullptr;
|
||||
g.m_dance_program = nullptr;
|
||||
|
||||
g_script_patcher_service->update();
|
||||
bLastDanceMode = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (g.self.dance_mode && g.m_dance_thread->m_handler)
|
||||
{
|
||||
*scr_globals::dance_state.as<PINT>() = TRUE; //Never once do the scripts read this as a boolean. It seems to be some kind of state the player is in. Runs from 4 to 35.
|
||||
scr_functions::dance_loop.call(g.m_dance_thread, g.m_dance_program, {});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "script_local.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include "util/math.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
static bool bLastLsCustoms = false;
|
||||
static bool bModshopReady = false;
|
||||
|
||||
void looped::vehicle_ls_customs()
|
||||
{
|
||||
if (g.vehicle.ls_customs && g.vehicle.ls_customs != bLastLsCustoms)
|
||||
{
|
||||
g_fiber_pool->queue_job([] {
|
||||
scripts::request_script("carmod_shop"_J);
|
||||
if (scripts::wait_till_loaded("carmod_shop"_J))
|
||||
{
|
||||
HUD::REQUEST_ADDITIONAL_TEXT("MOD_MNU", 9);
|
||||
|
||||
while (!HUD::HAS_THIS_ADDITIONAL_TEXT_LOADED("MOD_MNU", 9))
|
||||
script::get_current()->yield();
|
||||
|
||||
GRAPHICS::REQUEST_STREAMED_TEXTURE_DICT("CommonMenu", false);
|
||||
GRAPHICS::REQUEST_STREAMED_TEXTURE_DICT("MPShopSale", false);
|
||||
GRAPHICS::REQUEST_STREAMED_TEXTURE_DICT("ShopUI_Title_Los_Santos_Car_Meet", false);
|
||||
|
||||
// clang-format off
|
||||
while (!GRAPHICS::HAS_STREAMED_TEXTURE_DICT_LOADED("CommonMenu")
|
||||
|| !GRAPHICS::HAS_STREAMED_TEXTURE_DICT_LOADED("MPShopSale")
|
||||
|| !GRAPHICS::HAS_STREAMED_TEXTURE_DICT_LOADED("ShopUI_Title_Los_Santos_Car_Meet"))
|
||||
script::get_current()->yield();
|
||||
// clang-format on
|
||||
|
||||
auto id = SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH("carmod_shop"_J, 5050);
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
g.m_modshop_thread = gta_util::find_script_thread_by_id(id);
|
||||
if (!g.m_modshop_thread)
|
||||
return;
|
||||
|
||||
g.m_modshop_thread->m_context.m_state = rage::eThreadState::unk_3;
|
||||
scr_functions::modshop_loop.populate_ip();
|
||||
scr_functions::setup_modshop.populate_ip();
|
||||
|
||||
g_script_patcher_service->update();
|
||||
|
||||
scr_functions::setup_modshop.call_latent(g.m_modshop_thread, gta_util::find_script_program("carmod_shop"_J), {45, 0, 18, 0}, bModshopReady);
|
||||
*scr_locals::carmod_shop::maintainer.set(g.m_modshop_thread->m_stack).at(scr_locals::carmod_shop::state).as<PINT>() = 2;
|
||||
*scr_locals::carmod_shop::input_button.set(g.m_modshop_thread->m_stack).as<ControllerInputs*>() = ControllerInputs::INPUT_FRONTEND_LT;
|
||||
}
|
||||
});
|
||||
bLastLsCustoms = true;
|
||||
}
|
||||
else if (!g.vehicle.ls_customs && g.vehicle.ls_customs != bLastLsCustoms)
|
||||
{
|
||||
if (g.m_modshop_thread)
|
||||
g.m_modshop_thread->kill();
|
||||
|
||||
GRAPHICS::SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("CommonMenu");
|
||||
GRAPHICS::SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("MPShopSale");
|
||||
GRAPHICS::SET_STREAMED_TEXTURE_DICT_AS_NO_LONGER_NEEDED("ShopUI_Title_Los_Santos_Car_Meet");
|
||||
|
||||
g.m_modshop_thread = nullptr;
|
||||
bLastLsCustoms = false;
|
||||
bModshopReady = false;
|
||||
g_script_patcher_service->update();
|
||||
}
|
||||
|
||||
if (self::veh == 0 || SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) > 0 || (!g.m_modshop_thread && bModshopReady))
|
||||
{
|
||||
g.vehicle.ls_customs = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (g.vehicle.ls_customs && g.m_modshop_thread)
|
||||
{
|
||||
PAD::DISABLE_CONTROL_ACTION(0, (int)ControllerInputs::INPUT_VEH_CIN_CAM, true);
|
||||
|
||||
if (*scr_locals::carmod_shop::enabled_state.set(g.m_modshop_thread->m_stack).as<bool*>() && PAD::IS_CONTROL_JUST_PRESSED(2, (int)ControllerInputs::INPUT_FRONTEND_ACCEPT))
|
||||
g.vehicle.ls_customs = false;
|
||||
}
|
||||
|
||||
if (g.vehicle.ls_customs && bModshopReady && g.m_modshop_thread && g.m_modshop_thread->m_stack)
|
||||
{
|
||||
*scr_locals::carmod_shop::ready.set(g.m_modshop_thread->m_stack).as<PBOOL>() = FALSE;
|
||||
*scr_locals::carmod_shop::maintainer.set(g.m_modshop_thread->m_stack).at(scr_locals::carmod_shop::vehicle_state).as<PINT>() = -1;
|
||||
*scr_locals::carmod_shop::maintainer.set(g.m_modshop_thread->m_stack).at(scr_locals::carmod_shop::vehicle_ent_id).as<Vehicle*>() = self::veh;
|
||||
|
||||
if (*scr_locals::carmod_shop::maintainer.set(g.m_modshop_thread->m_stack).at(scr_locals::carmod_shop::state).as<PINT>() == 0)
|
||||
*scr_locals::carmod_shop::maintainer.set(g.m_modshop_thread->m_stack).at(scr_locals::carmod_shop::state).as<PINT>() = 2;
|
||||
|
||||
scr_functions::modshop_loop.call(g.m_modshop_thread, gta_util::find_script_program("carmod_shop"_J), {});
|
||||
}
|
||||
}
|
||||
}
|
@ -20,17 +20,13 @@ namespace big
|
||||
g_script_patcher_service->add_patch({"freemode"_J, "prevent normal blip update 2", "2C ? ? ? 55 ? ? 71 2C ? ? ? 61", 7, std::vector<uint8_t>(16, 0x0), &g.spoofing.spoof_blip}); // prevent normal blip update 2
|
||||
g_script_patcher_service->add_patch({"freemode"_J, "stop relinquishing invalid CEO slots", "2D 01 05 00 00 38 00 2C ? ? ? 39 03 38 03 2C ? ? ? 56", 5, {0x2E, 0x01, 0x00}, &g.session.block_ceo_creation}); // stop relinquishing invalid CEO slots
|
||||
g_script_patcher_service->add_patch({"freemode"_J, "prevent NPC bounties", "2D 04 06 00 00 25 1D", 5, {0x2E, 0x04, 0x00}, &g.protections.script_events.bounty}); // disable NPCs putting bounties on us.
|
||||
g_script_patcher_service->add_patch({"shop_controller"_J, "despawn bypass", "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, {0x71, 0x2E, 0x01, 0x01}, nullptr}); // despawn bypass
|
||||
g_script_patcher_service->add_patch({"shop_controller"_J, "godmode/invisibility detection bypass", "2D 01 03 00 00 5D ? ? ? 06 56 ? ? 2E ? ? 2C", 5, {0x2E, 0x01, 0x00}, nullptr}); // godmode/invisibility detection bypass
|
||||
g_script_patcher_service->add_patch({"am_mp_nightclub"_J, "am_mp_nightclub1", "2D 01 03 00 00 2C ? ? ? 56 ? ? 72 2E ? ? 38 00", 5, {0x72, 0x2E, 0x01, 0x01}, &g.self.dance_mode});
|
||||
g_script_patcher_service->add_patch({"am_mp_nightclub"_J, "am_mp_nightclub2", "20 56 ? ? 4F ? ? 46 ? ? 41 ? 71", 0, {0x2B, 0x55}, &g.self.dance_mode});
|
||||
g_script_patcher_service->add_patch({"freemode"_J, "freemode9", "5D ? ? ? 56 ? ? 72 39 05 38 04 2C ? ? ? 58", 0, {0x2B, 0x2B, 0x2B, 0x00, 0x55}, &g.self.invisibility});
|
||||
g_script_patcher_service->add_patch({"freemode"_J, "freemode10", "2D 01 03 00 00 38 00 71 72 5D ? ? ? 06 56 ? ? 71 2E ? ? 2C ? ? ? 71", 5, {0x72, 0x2E, 0x01, 0x01}, &g.session.unhide_players_from_player_list});
|
||||
g_script_patcher_service->add_patch({"carmod_shop"_J, "disable camera", "2D 01 0A 00 00 4F ? ? 40 ? 41 ? 39 03", 5, {0x2E, 0x01, 0x00}, &g.vehicle.ls_customs}); // disable camera
|
||||
g_script_patcher_service->add_patch({"carmod_shop"_J, "carmod_shop1", "2D 02 10 00 00 2C", 5, {0x71, 0x2E, 0x02, 0x01}, &g.vehicle.ls_customs});
|
||||
g_script_patcher_service->add_patch({"carmod_shop"_J, "carmod_shop2", "2D 00 B8 00 00", 5, {0x2E, 0x00, 0x00}, &g.vehicle.ls_customs});
|
||||
g_script_patcher_service->add_patch({"shop_controller"_J, "despawn bypass", "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, {0x71, 0x2E, 0x01, 0x01}, nullptr}); // despawn bypass
|
||||
g_script_patcher_service->add_patch({"shop_controller"_J, "godmode/invisibility detection bypass", "2D 01 03 00 00 5D ? ? ? 06 56 ? ? 2E ? ? 2C", 5, {0x2E, 0x01, 0x00}, nullptr}); // godmode/invisibility detection bypass
|
||||
g_script_patcher_service->add_patch({"carmod_shop"_J, "allow all vehicles", "2D 03 16 00 00 38 00", 5, {0x72, 0x2E, 0x03, 0x01}, nullptr}); // allow all vehicles
|
||||
g_script_patcher_service->add_patch({"carmod_shop"_J, "allow all vehicles 2", "2D 03 07 00 00 71 38 02", 5, {0x72, 0x2E, 0x03, 0x01}, nullptr}); // allow all vehicles 2
|
||||
g_script_patcher_service->add_patch({"main_persistent"_J, "vehicle clan logo SP bypass", "56 04 00 72 2E 01 01 2C 01 04 1F 5D ? ? ? 74", 0, {0x55}, nullptr}); // vehicle clan logo SP bypass
|
||||
|
||||
for (auto& entry : *g_pointers->m_gta.m_script_program_table)
|
||||
{
|
||||
|
@ -37,8 +37,6 @@ namespace big::scr_globals
|
||||
static inline const script_global freemode_global(2738934);
|
||||
|
||||
static inline const script_global spawn_global(2696212);
|
||||
|
||||
static inline const script_global dance_state(1943520);
|
||||
|
||||
static inline const script_global transaction_overlimit(20913);
|
||||
|
||||
@ -107,15 +105,4 @@ namespace big::scr_locals
|
||||
// func_\d+\((&.Local_\d+(, )?){9}\);
|
||||
inline static script_local mobile(19139);
|
||||
}
|
||||
|
||||
namespace carmod_shop
|
||||
{
|
||||
inline static script_local maintainer(735); //P"4F ? ? 47 ? ? 73 58 ? ? 4F ? ? 25 ?" +1 W="maintainer" +3 W ="state"
|
||||
inline static auto state = 446;
|
||||
inline static script_local input_button(1867); //P"51 ? ? 70 51 ? ? 50 ? ? 51 ? ?" +1 W="input_button"
|
||||
inline static script_local enabled_state(2097); //P"51 ? ? 71 51 ? ? 71 51 ? ? 71 61 ? ? ?" +1 W="enabled_state"
|
||||
inline static script_local ready(2048); //P"51 ? ? 50 ? ? 2A" +1 W="ready"
|
||||
inline static auto vehicle_state = 638; //P"4F ? ? 46 ? ? 4F ? ?" +4 W ="vehicle_state"
|
||||
inline static auto vehicle_ent_id = 409; //P"4F ? ? 47 ? ? 39 ? 55 ? ? 38 ? 73" +4 W ="vehicle_ent_id"
|
||||
}
|
||||
}
|
||||
|
@ -80,9 +80,6 @@ namespace big
|
||||
|
||||
rage::scrThread* m_hunt_the_beast_thread = nullptr;
|
||||
|
||||
rage::scrThread* m_dance_thread = nullptr;
|
||||
rage::scrProgram* m_dance_program = nullptr;
|
||||
|
||||
rage::scrThread* m_mission_creator_thread = nullptr;
|
||||
|
||||
struct script_block_opts
|
||||
@ -114,8 +111,7 @@ namespace big
|
||||
bool enabled = false;
|
||||
} cmd_executor{};
|
||||
|
||||
rage::scrThread* m_modshop_thread = nullptr;
|
||||
bool in_script_vm = false;
|
||||
bool in_script_vm = false;
|
||||
|
||||
struct debug
|
||||
{
|
||||
@ -396,8 +392,6 @@ namespace big
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(hud, color_override, color_override_initialized, hud_color_overrides, hide_radar, hide_ammo, selected_hud_component, hud_components_states, force_show_hud_element, force_show_hud)
|
||||
} hud{};
|
||||
// do not save below entries
|
||||
bool dance_mode = false;
|
||||
|
||||
struct super_hero_fly
|
||||
{
|
||||
@ -413,7 +407,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, never_wanted, force_wanted_level, passive, free_cam, invisibility, local_visibility, 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, 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)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ipls, ptfx_effects, clean_player, never_wanted, force_wanted_level, passive, free_cam, invisibility, local_visibility, 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, 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, graceful_landing)
|
||||
|
||||
} self{};
|
||||
|
||||
@ -806,7 +800,6 @@ namespace big
|
||||
bool instant_brake = false;
|
||||
bool infinite_veh_ammo = false;
|
||||
bool block_homing = true;
|
||||
bool ls_customs = false; // don't save this to disk
|
||||
bool seatbelt = false;
|
||||
bool turn_signals = false;
|
||||
bool vehicle_jump = false;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,6 @@
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
#include <script/globals/GPBD_FM_3.hpp>
|
||||
#include <script/globals/GlobalPlayerBD.hpp>
|
||||
#include <script/CGameScriptHandlerNetComponent.hpp>
|
||||
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -17,15 +17,9 @@ namespace big
|
||||
if (thread == g.m_hunt_the_beast_thread)
|
||||
g.m_hunt_the_beast_thread = nullptr;
|
||||
|
||||
if (thread == g.m_dance_thread)
|
||||
g.m_dance_thread = nullptr;
|
||||
|
||||
if (thread == g.m_mission_creator_thread)
|
||||
g.m_mission_creator_thread = nullptr;
|
||||
|
||||
if (thread == g.m_modshop_thread)
|
||||
g.m_modshop_thread = nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -625,12 +625,14 @@ namespace lua::memory
|
||||
pointer_ut["add"] = &pointer::add;
|
||||
pointer_ut["sub"] = &pointer::sub;
|
||||
pointer_ut["rip"] = &pointer::rip;
|
||||
pointer_ut["get_int"] = &pointer::get<int32_t>;
|
||||
pointer_ut["get_byte"] = &pointer::get<uint8_t>;
|
||||
pointer_ut["get_word"] = &pointer::get<uint16_t>;
|
||||
pointer_ut["get_dword"] = &pointer::get<uint32_t>;
|
||||
pointer_ut["get_qword"] = &pointer::get<uint64_t>;
|
||||
pointer_ut["get_float"] = &pointer::get<float>;
|
||||
pointer_ut["get_string"] = &pointer::get_string;
|
||||
pointer_ut["set_int"] = &pointer::set<int32_t>;
|
||||
pointer_ut["set_byte"] = &pointer::set<uint8_t>;
|
||||
pointer_ut["set_word"] = &pointer::set<uint16_t>;
|
||||
pointer_ut["set_dword"] = &pointer::set<uint32_t>;
|
||||
|
@ -137,6 +137,10 @@ namespace lua::memory
|
||||
{
|
||||
return type_info_t::double_;
|
||||
}
|
||||
else if (s.contains("vector3"))
|
||||
{
|
||||
return type_info_t::vector3_;
|
||||
}
|
||||
else
|
||||
{
|
||||
return type_info_t::integer_;
|
||||
|
360
src/lua/bindings/scr_function.cpp
Normal file
360
src/lua/bindings/scr_function.cpp
Normal file
@ -0,0 +1,360 @@
|
||||
#include "scr_function.hpp"
|
||||
|
||||
#include "gta_util.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "memory/pattern.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
namespace lua::scr_function
|
||||
{
|
||||
template<typename Arg>
|
||||
void push_arg(uint64_t* stack, uint32_t& stack_pointer, Arg&& value)
|
||||
{
|
||||
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<Arg>>*>(reinterpret_cast<uint64_t*>(stack) + (stack_pointer++)) = std::forward<Arg>(value);
|
||||
}
|
||||
|
||||
// Lua API: Table
|
||||
// Name: scr_function
|
||||
// Table for calling GTA script functions. Needs to be called in the fiber pool. Only call the function when necessary.
|
||||
|
||||
// Lua API: function
|
||||
// Table: scr_function
|
||||
// Name: call_script_function
|
||||
// Param: script_name: string: Name of the script.
|
||||
// Param: function_name: string: Name of the function. This parameter needs to be unique.
|
||||
// Param: pattern: string: Pattern to scan for within the script.
|
||||
// Param: return_type_string: string: Return type of the function. Supported types are **"int"**, **"bool"**, **"const char\*/string"**, **"ptr/pointer/*"**, **"float"**, and **"vector3"**. Anything different will be rejected.
|
||||
// Param: args_: table: Arguments to pass to the function. Supported types are the same as return types.
|
||||
// Calls a script function with the given arguments. Returns the return value as the given type.
|
||||
// **Example Usage:**
|
||||
// ```lua
|
||||
// local value = scr_function.call_script_function("freemode", "wear_sunglasses_at_night", "69 42 06 66", "bool", {
|
||||
// { "int", 69 },
|
||||
// { "float", 4.20 },
|
||||
// { "int", 666 }
|
||||
// })
|
||||
// ```
|
||||
|
||||
static sol::object call_script_function_by_signature(const std::string& script_name, const std::string& function_name, const std::string& pattern, const std::string& return_type_string, sol::table args_, sol::this_state state_)
|
||||
{
|
||||
std::vector<lua::memory::type_info_t> param_types;
|
||||
std::vector<sol::object> actual_args;
|
||||
static std::unordered_map<std::string, int32_t> pattern_results;
|
||||
for (const auto& [k, v_] : args_)
|
||||
{
|
||||
if (v_.is<sol::table>())
|
||||
{
|
||||
auto v = v_.as<sol::table>();
|
||||
param_types.push_back(lua::memory::get_type_info_from_string(v[1].get<const char*>()));
|
||||
actual_args.push_back(v[2].get<sol::object>());
|
||||
}
|
||||
}
|
||||
|
||||
const auto return_type = lua::memory::get_type_info_from_string(return_type_string);
|
||||
|
||||
auto thread = big::gta_util::find_script_thread(rage::joaat(script_name));
|
||||
auto program = big::gta_util::find_script_program(rage::joaat(script_name));
|
||||
|
||||
if (!thread || !program)
|
||||
{
|
||||
LOG(FATAL) << "Failed to find " << script_name << " for " << function_name;
|
||||
return sol::lua_nil;
|
||||
}
|
||||
|
||||
int32_t instruction_pointer;
|
||||
|
||||
if (pattern_results.contains(function_name))
|
||||
{
|
||||
instruction_pointer = pattern_results[function_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
const ::memory::pattern pattern_scan(pattern);
|
||||
|
||||
auto location = big::scripts::get_code_location_by_pattern(program, pattern_scan);
|
||||
|
||||
if (!location)
|
||||
{
|
||||
LOG(FATAL) << "Failed to find pattern " << function_name << " in script " << script_name;
|
||||
return sol::lua_nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(VERBOSE) << "Found pattern for " << function_name << " at " << HEX_TO_UPPER(location.value()) << " in " << script_name;
|
||||
}
|
||||
|
||||
pattern_results[function_name] = instruction_pointer = location.value();
|
||||
}
|
||||
|
||||
auto tls_ctx = rage::tlsContext::get();
|
||||
auto stack = (uint64_t*)thread->m_stack;
|
||||
auto og_thread = tls_ctx->m_script_thread;
|
||||
tls_ctx->m_script_thread = thread;
|
||||
tls_ctx->m_is_script_thread_active = true;
|
||||
rage::scrThreadContext ctx = thread->m_context;
|
||||
auto top_stack = ctx.m_stack_pointer; // This will be the top item in the stack after the args and return address are cleaned off
|
||||
|
||||
for (size_t i = 0; i < param_types.size(); i++)
|
||||
{
|
||||
switch (param_types[i])
|
||||
{
|
||||
case lua::memory::type_info_t::boolean_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<bool>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::string_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<const char*>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::integer_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<int>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::ptr_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<lua::memory::pointer>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, (*val).get_address());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::float_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<float>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::vector3_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<Vector3>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().x);
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().y);
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
stack[ctx.m_stack_pointer++] = 0;
|
||||
ctx.m_instruction_pointer = instruction_pointer;
|
||||
ctx.m_state = rage::eThreadState::idle;
|
||||
|
||||
big::g_pointers->m_gta.m_script_vm(stack, big::g_pointers->m_gta.m_script_globals, program, &ctx);
|
||||
|
||||
tls_ctx->m_script_thread = og_thread;
|
||||
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
|
||||
|
||||
if (return_type == lua::memory::type_info_t::boolean_)
|
||||
{
|
||||
return sol::make_object(state_, (bool)*reinterpret_cast<BOOL*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::string_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<const char**>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::integer_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<int*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::ptr_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<uint64_t*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::float_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<float*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::vector3_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<Vector3*>(stack + top_stack));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(FATAL) << "Unimplemented return type " << return_type_string;
|
||||
return sol::lua_nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Lua API: function
|
||||
// Table: scr_function
|
||||
// Name: call_script_function
|
||||
// Param: script_name: string: Name of the script.
|
||||
// Param: instruction_pointer: integer: Position of the function within the script.
|
||||
// Param: return_type_string: string: Return type of the function. Supported types are **"int"**, **"bool"**, **"const char\*/string"**, **"ptr/pointer/*"**, **"float"**, and **"vector3"**. Anything different will be rejected.
|
||||
// Param: args_: table: Arguments to pass to the function. Supported types are the same as return types.
|
||||
// Calls a script function directly using the function position with the given arguments. Returns the return value as the given type.
|
||||
// **Example Usage:**
|
||||
// ```lua
|
||||
// local value = scr_function.call_script_function("freemode", 0xE792, "string", {
|
||||
// { "int", 191 }
|
||||
// })
|
||||
// ```
|
||||
|
||||
static sol::object call_script_function_by_instruction_pointer(const std::string& script_name, const int instruction_pointer, const std::string& return_type_string, sol::table args_, sol::this_state state_)
|
||||
{
|
||||
std::vector<lua::memory::type_info_t> param_types;
|
||||
std::vector<sol::object> actual_args;
|
||||
for (const auto& [k, v_] : args_)
|
||||
{
|
||||
if (v_.is<sol::table>())
|
||||
{
|
||||
auto v = v_.as<sol::table>();
|
||||
param_types.push_back(lua::memory::get_type_info_from_string(v[1].get<const char*>()));
|
||||
actual_args.push_back(v[2].get<sol::object>());
|
||||
}
|
||||
}
|
||||
|
||||
const auto return_type = lua::memory::get_type_info_from_string(return_type_string);
|
||||
|
||||
auto thread = big::gta_util::find_script_thread(rage::joaat(script_name));
|
||||
auto program = big::gta_util::find_script_program(rage::joaat(script_name));
|
||||
|
||||
if (!thread || !program || !instruction_pointer)
|
||||
{
|
||||
LOG(FATAL) << "Failed to run " << script_name << " script function at " << HEX_TO_UPPER(instruction_pointer);
|
||||
return sol::lua_nil;
|
||||
}
|
||||
|
||||
auto tls_ctx = rage::tlsContext::get();
|
||||
auto stack = (uint64_t*)thread->m_stack;
|
||||
auto og_thread = tls_ctx->m_script_thread;
|
||||
tls_ctx->m_script_thread = thread;
|
||||
tls_ctx->m_is_script_thread_active = true;
|
||||
rage::scrThreadContext ctx = thread->m_context;
|
||||
auto top_stack = ctx.m_stack_pointer; // This will be the top item in the stack after the args and return address are cleaned off
|
||||
|
||||
for (size_t i = 0; i < param_types.size(); i++)
|
||||
{
|
||||
switch (param_types[i])
|
||||
{
|
||||
case lua::memory::type_info_t::boolean_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<bool>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::string_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<const char*>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::integer_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<int>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::ptr_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<lua::memory::pointer>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, (*val).get_address());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::float_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<float>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, *val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case lua::memory::type_info_t::vector3_:
|
||||
{
|
||||
const auto val = actual_args[i].as<std::optional<Vector3>>();
|
||||
if (val)
|
||||
{
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().x);
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().y);
|
||||
push_arg(stack, ctx.m_stack_pointer, val.value().z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
stack[ctx.m_stack_pointer++] = 0;
|
||||
ctx.m_instruction_pointer = instruction_pointer;
|
||||
ctx.m_state = rage::eThreadState::idle;
|
||||
|
||||
big::g_pointers->m_gta.m_script_vm(stack, big::g_pointers->m_gta.m_script_globals, program, &ctx);
|
||||
|
||||
tls_ctx->m_script_thread = og_thread;
|
||||
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
|
||||
|
||||
if (return_type == lua::memory::type_info_t::boolean_)
|
||||
{
|
||||
return sol::make_object(state_, (bool)*reinterpret_cast<BOOL*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::string_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<const char**>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::integer_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<int*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::ptr_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<uint64_t*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::float_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<float*>(stack + top_stack));
|
||||
}
|
||||
else if (return_type == lua::memory::type_info_t::vector3_)
|
||||
{
|
||||
return sol::make_object(state_, *reinterpret_cast<Vector3*>(stack + top_stack));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(FATAL) << "Unimplemented return type " << return_type_string;
|
||||
return sol::lua_nil;
|
||||
}
|
||||
}
|
||||
|
||||
void bind(sol::state& state)
|
||||
{
|
||||
auto ns = state["scr_function"].get_or_create<sol::table>();
|
||||
|
||||
ns["call_script_function"] = sol::overload(call_script_function_by_signature, call_script_function_by_instruction_pointer);
|
||||
}
|
||||
}
|
8
src/lua/bindings/scr_function.hpp
Normal file
8
src/lua/bindings/scr_function.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "script_function.hpp"
|
||||
|
||||
namespace lua::scr_function
|
||||
{
|
||||
void bind(sol::state& state);
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "lua/lua_manager.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "lua/bindings/network.hpp"
|
||||
#include "memory/pattern.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
@ -204,27 +203,6 @@ namespace lua::script
|
||||
if (auto program = big::gta_util::find_script_program(rage::joaat(script_name)))
|
||||
big::g_script_patcher_service->on_script_load(program);
|
||||
}
|
||||
|
||||
// Lua API: function
|
||||
// Table: script
|
||||
// Name: call_function
|
||||
// Param: name: string: The name of the script function.
|
||||
// Param: script_name: string: The name of the script.
|
||||
// Param: pattern: string: The pattern to scan for within the script.
|
||||
// Param offset: integer: The position within the pattern.
|
||||
// Param _args: table: The arguments to pass to the script function.
|
||||
// Calls a function from the specified script.
|
||||
// **Example Usage:**
|
||||
// ```lua
|
||||
// script.call_function("Collect Collectible", "freemode", "2D 05 33 00 00", 0, {17, 0, 1, 1, 0})
|
||||
// ```
|
||||
static void call_function(const std::string& name, const std::string& script_name, const std::string& pattern, int offset, sol::table _args)
|
||||
{
|
||||
auto args = convert_sequence<uint64_t>(_args);
|
||||
|
||||
big::script_function script_function(name, rage::joaat(script_name), pattern, offset);
|
||||
script_function(args);
|
||||
}
|
||||
|
||||
// Lua API: function
|
||||
// Table: script
|
||||
@ -250,7 +228,6 @@ namespace lua::script
|
||||
ns["is_active"] = is_active;
|
||||
ns["execute_as_script"] = execute_as_script;
|
||||
ns["add_patch"] = add_patch;
|
||||
ns["call_function"] = call_function;
|
||||
ns["start_launcher_script"] = start_launcher_script;
|
||||
|
||||
auto usertype = state.new_usertype<script_util>("script_util");
|
||||
|
@ -10,6 +10,7 @@ namespace lua::memory
|
||||
integer_,
|
||||
ptr_,
|
||||
float_,
|
||||
double_
|
||||
double_,
|
||||
vector3_
|
||||
};
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
#include "bindings/native.hpp"
|
||||
#include "bindings/network.hpp"
|
||||
#include "bindings/script.hpp"
|
||||
#include "bindings/scr_function.hpp"
|
||||
#include "bindings/self.hpp"
|
||||
#include "bindings/stats.hpp"
|
||||
#include "bindings/tunables.hpp"
|
||||
@ -298,6 +299,7 @@ namespace big
|
||||
lua::log::bind(m_state);
|
||||
lua::globals::bind(m_state);
|
||||
lua::script::bind(m_state);
|
||||
lua::scr_function::bind(m_state);
|
||||
lua::native::bind(m_state);
|
||||
lua::memory::bind(m_state);
|
||||
lua::gui::bind(m_state);
|
||||
|
@ -236,7 +236,6 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::vehicles_loop, "Vehicle"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::misc_loop, "Miscellaneous"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::remote_loop, "Remote"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::lscustoms_loop, "LS Customs"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::rainbowpaint_loop, "Rainbow Paint"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::disable_control_action_loop, "Disable Controls"));
|
||||
g_script_mgr.add_script(std::make_unique<script>(&backend::world_loop, "World"));
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "script_function.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
#include "native_hooks.hpp"
|
||||
#include "natives.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
namespace carmod_shop
|
||||
{
|
||||
inline void SET_ENTITY_COORDS(rage::scrNativeCallContext* src)
|
||||
{
|
||||
if (!g.vehicle.ls_customs)
|
||||
{
|
||||
ENTITY::SET_ENTITY_COORDS(src->get_arg<Entity>(0), src->get_arg<float>(1), src->get_arg<float>(2), src->get_arg<float>(3), src->get_arg<BOOL>(4), src->get_arg<BOOL>(5), src->get_arg<BOOL>(6), src->get_arg<BOOL>(7));
|
||||
}
|
||||
}
|
||||
|
||||
inline void SET_ENTITY_HEADING(rage::scrNativeCallContext* src)
|
||||
{
|
||||
if (!g.vehicle.ls_customs)
|
||||
{
|
||||
ENTITY::SET_ENTITY_HEADING(src->get_arg<Entity>(0), src->get_arg<float>(1));
|
||||
}
|
||||
}
|
||||
|
||||
inline void SET_VEHICLE_LIGHTS(rage::scrNativeCallContext* src)
|
||||
{
|
||||
if (!g.vehicle.ls_customs)
|
||||
{
|
||||
VEHICLE::SET_VEHICLE_LIGHTS(src->get_arg<Vehicle>(0), src->get_arg<int>(1));
|
||||
}
|
||||
}
|
||||
|
||||
inline void DISABLE_ALL_CONTROL_ACTIONS(rage::scrNativeCallContext* src)
|
||||
{
|
||||
if (!g.vehicle.ls_customs)
|
||||
{
|
||||
PAD::DISABLE_ALL_CONTROL_ACTIONS(src->get_arg<int>(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -73,7 +73,7 @@ namespace big
|
||||
{
|
||||
if (SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME() == "freemode"_J && g.session.fast_join)
|
||||
{
|
||||
scr_functions::set_freemode_session_active({});
|
||||
scr_functions::set_freemode_session_active.call<void>();
|
||||
src->set_return_value<BOOL>(TRUE);
|
||||
}
|
||||
else
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "all_scripts.hpp"
|
||||
#include "am_launcher.hpp"
|
||||
#include "am_pi_menu.hpp"
|
||||
#include "carmod_shop.hpp"
|
||||
#include "creator.hpp"
|
||||
#include "freemode.hpp"
|
||||
#include "network_session_host.hpp"
|
||||
@ -104,11 +103,6 @@ namespace big
|
||||
add_native_detour("shop_controller"_J, NativeIndex::SET_WARNING_MESSAGE_WITH_HEADER, shop_controller::SET_WARNING_MESSAGE_WITH_HEADER);
|
||||
add_native_detour("shop_controller"_J, NativeIndex::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT, shop_controller::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT);
|
||||
|
||||
add_native_detour("carmod_shop"_J, NativeIndex::SET_ENTITY_COORDS, carmod_shop::SET_ENTITY_COORDS);
|
||||
add_native_detour("carmod_shop"_J, NativeIndex::SET_ENTITY_HEADING, carmod_shop::SET_ENTITY_HEADING);
|
||||
add_native_detour("carmod_shop"_J, NativeIndex::SET_VEHICLE_LIGHTS, carmod_shop::SET_VEHICLE_LIGHTS);
|
||||
add_native_detour("carmod_shop"_J, NativeIndex::DISABLE_ALL_CONTROL_ACTIONS, carmod_shop::DISABLE_ALL_CONTROL_ACTIONS);
|
||||
|
||||
add_native_detour("freemode"_J, NativeIndex::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH, freemode::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH);
|
||||
add_native_detour("freemode"_J, NativeIndex::STAT_GET_INT, freemode::STAT_GET_INT);
|
||||
add_native_detour("freemode"_J, NativeIndex::IS_PLAYER_PLAYING, freemode::IS_PLAYER_PLAYING);
|
||||
|
@ -1,136 +1,30 @@
|
||||
#include "script_function.hpp"
|
||||
|
||||
#include "gta_util.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
#include <script/scrProgram.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
script_function::script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern, int32_t offset) :
|
||||
script_function::script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern) :
|
||||
m_name(name),
|
||||
m_script(script),
|
||||
m_pattern(pattern),
|
||||
m_offset(offset),
|
||||
m_ip(0)
|
||||
{
|
||||
}
|
||||
|
||||
void script_function::populate_ip()
|
||||
uint32_t script_function::get_ip(rage::scrProgram* program)
|
||||
{
|
||||
if (m_ip == 0)
|
||||
if (m_ip != 0)
|
||||
return m_ip;
|
||||
|
||||
if (auto location = scripts::get_code_location_by_pattern(program, m_pattern))
|
||||
{
|
||||
auto program = gta_util::find_script_program(m_script);
|
||||
|
||||
if (!program)
|
||||
return;
|
||||
|
||||
auto location = scripts::get_code_location_by_pattern(program, m_pattern);
|
||||
|
||||
if (!location)
|
||||
LOG(FATAL) << "Failed to find pattern " << m_name << " in script " << program->m_name;
|
||||
else
|
||||
LOG(VERBOSE) << "Found pattern " << m_name << " in script " << program->m_name;
|
||||
|
||||
m_ip = location.value() + m_offset;
|
||||
m_ip = *location;
|
||||
LOG(VERBOSE) << "Found pattern " << m_name << " at " << HEX_TO_UPPER(m_ip) << " in script " << program->m_name;
|
||||
}
|
||||
}
|
||||
|
||||
void script_function::call(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args)
|
||||
{
|
||||
auto tls_ctx = rage::tlsContext::get();
|
||||
auto stack = (uint64_t*)thread->m_stack;
|
||||
auto og_thread = tls_ctx->m_script_thread;
|
||||
|
||||
tls_ctx->m_script_thread = thread;
|
||||
tls_ctx->m_is_script_thread_active = true;
|
||||
|
||||
rage::scrThreadContext ctx = thread->m_context;
|
||||
|
||||
for (const auto& arg : args)
|
||||
stack[ctx.m_stack_pointer++] = arg;
|
||||
|
||||
stack[ctx.m_stack_pointer++] = 0;
|
||||
ctx.m_instruction_pointer = m_ip;
|
||||
ctx.m_state = rage::eThreadState::idle;
|
||||
|
||||
g_pointers->m_gta.m_script_vm(stack, g_pointers->m_gta.m_script_globals, program, &ctx);
|
||||
|
||||
tls_ctx->m_script_thread = og_thread;
|
||||
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
|
||||
}
|
||||
|
||||
void script_function::call_latent(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args, bool& done)
|
||||
{
|
||||
g_fiber_pool->queue_job([this, thread, program, args, &done] {
|
||||
auto stack = (uint64_t*)thread->m_stack;
|
||||
|
||||
rage::eThreadState result = rage::eThreadState::idle;
|
||||
|
||||
rage::scrThreadContext ctx = thread->m_context;
|
||||
|
||||
for (const auto& arg : args)
|
||||
stack[ctx.m_stack_pointer++] = arg;
|
||||
|
||||
stack[ctx.m_stack_pointer++] = 0;
|
||||
ctx.m_instruction_pointer = m_ip;
|
||||
ctx.m_state = rage::eThreadState::idle;
|
||||
|
||||
while (result != rage::eThreadState::killed)
|
||||
{
|
||||
auto tls_ctx = rage::tlsContext::get();
|
||||
auto og_thread = tls_ctx->m_script_thread;
|
||||
|
||||
tls_ctx->m_script_thread = thread;
|
||||
tls_ctx->m_is_script_thread_active = true;
|
||||
|
||||
auto old_ctx = thread->m_context;
|
||||
thread->m_context = ctx;
|
||||
result = g_pointers->m_gta.m_script_vm(stack, g_pointers->m_gta.m_script_globals, program, &thread->m_context);
|
||||
thread->m_context = old_ctx;
|
||||
|
||||
tls_ctx->m_script_thread = og_thread;
|
||||
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
|
||||
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
done = true;
|
||||
});
|
||||
}
|
||||
|
||||
void script_function::static_call(const std::vector<uint64_t>& args)
|
||||
{
|
||||
populate_ip();
|
||||
|
||||
rage::scrThread* thread = (rage::scrThread*)new uint8_t[sizeof(rage::scrThread)];
|
||||
memcpy(thread, rage::tlsContext::get()->m_script_thread, sizeof(rage::scrThread));
|
||||
|
||||
void* stack = new uint64_t[25000];
|
||||
thread->m_stack = (rage::scrValue*)stack;
|
||||
thread->m_context.m_stack_size = 25000;
|
||||
thread->m_context.m_stack_pointer = 1;
|
||||
|
||||
call(thread, gta_util::find_script_program(m_script), args);
|
||||
|
||||
delete[] stack;
|
||||
delete[] (uint8_t*)thread; // without the cast it ends up calling the destructor which leads to some pretty funny crashes
|
||||
}
|
||||
|
||||
void script_function::operator()(const std::vector<uint64_t>& args)
|
||||
{
|
||||
populate_ip();
|
||||
|
||||
if (m_ip == 0)
|
||||
return;
|
||||
|
||||
auto thread = gta_util::find_script_thread(m_script);
|
||||
auto program = gta_util::find_script_program(m_script);
|
||||
|
||||
if (thread && program)
|
||||
else
|
||||
{
|
||||
call(thread, program, args);
|
||||
LOG(FATAL) << "Failed to find pattern " << m_name << " in script " << program->m_name;
|
||||
}
|
||||
|
||||
return m_ip;
|
||||
}
|
||||
}
|
@ -1,43 +1,74 @@
|
||||
#pragma once
|
||||
#include "gta/joaat.hpp"
|
||||
#include "memory/pattern.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
// a lightweight script function wrapper inspired by https://github.com/Parik27/V.Rainbomizer/blob/master/src/mission/missions_YscUtils.hh
|
||||
class script_function
|
||||
{
|
||||
rage::joaat_t m_script;
|
||||
const memory::pattern m_pattern;
|
||||
int32_t m_offset;
|
||||
int32_t m_ip;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern, int32_t offset);
|
||||
void populate_ip();
|
||||
void call(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args);
|
||||
void call_latent(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args, bool& done);
|
||||
|
||||
// for pure functions that do not need access to thread stack
|
||||
void static_call(const std::vector<uint64_t>& args);
|
||||
|
||||
void operator()(const std::vector<uint64_t>& args);
|
||||
};
|
||||
|
||||
namespace scr_functions
|
||||
{
|
||||
static inline script_function join_ceo("JC", "freemode"_J, "2D 04 1D 00 00 5D", 0);
|
||||
static inline script_function set_freemode_session_active("SFSA", "freemode"_J, "2D 00 02 00 00 75 5D ? ? ? 50", 0);
|
||||
static inline script_function dance_loop("DL", "am_mp_nightclub"_J, "2D 00 14 00 00 4F ? ? 47 ? ? 5D ? ? ? 56", 0);
|
||||
static inline script_function init_nightclub_script("INS", "am_mp_nightclub"_J, "2D 00 11 00 00 4F", 0);
|
||||
|
||||
static inline script_function save_to_datafile("STD", "fm_race_creator"_J, "2D 01 03 00 00 71 2C", 0);
|
||||
static inline script_function load_from_datafile("LFD", "fm_race_creator"_J, "2D 04 0D 00 00 71 2C", 0);
|
||||
|
||||
static inline script_function modshop_loop("ML", "carmod_shop"_J, "2D 00 07 00 00 71 51", 0);
|
||||
static inline script_function setup_modshop("SM", "carmod_shop"_J, "2D 04 12 00 00 38 00 51", 0);
|
||||
|
||||
static inline script_function reset_session_data("RSD", "pausemenu_multiplayer"_J, "2D 02 7D 00 00", 0);
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "gta_util.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
#include <script/scrProgram.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
class script_function
|
||||
{
|
||||
rage::joaat_t m_script;
|
||||
const memory::pattern m_pattern;
|
||||
uint32_t m_ip;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern);
|
||||
uint32_t get_ip(rage::scrProgram* program);
|
||||
|
||||
template<typename Arg>
|
||||
void push_arg(uint64_t* stack, uint32_t& stack_pointer, Arg&& value)
|
||||
{
|
||||
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<Arg>>*>(reinterpret_cast<uint64_t*>(stack) + (stack_pointer++)) = std::forward<Arg>(value);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(Args... args)
|
||||
{
|
||||
auto thread = gta_util::find_script_thread(m_script);
|
||||
auto program = gta_util::find_script_program(m_script);
|
||||
auto ip = get_ip(program);
|
||||
|
||||
if (!thread || !program || !ip)
|
||||
return Ret();
|
||||
|
||||
auto tls_ctx = rage::tlsContext::get();
|
||||
auto stack = (uint64_t*)thread->m_stack;
|
||||
auto og_thread = tls_ctx->m_script_thread;
|
||||
tls_ctx->m_script_thread = thread;
|
||||
tls_ctx->m_is_script_thread_active = true;
|
||||
rage::scrThreadContext ctx = thread->m_context;
|
||||
auto top_stack = ctx.m_stack_pointer; // This will be the top item in the stack after the args and return address are cleaned off
|
||||
|
||||
(push_arg(stack, ctx.m_stack_pointer, std::forward<Args>(args)), ...);
|
||||
|
||||
stack[ctx.m_stack_pointer++] = 0;
|
||||
ctx.m_instruction_pointer = ip;
|
||||
ctx.m_state = rage::eThreadState::idle;
|
||||
|
||||
g_pointers->m_gta.m_script_vm(stack, g_pointers->m_gta.m_script_globals, program, &ctx);
|
||||
|
||||
tls_ctx->m_script_thread = og_thread;
|
||||
tls_ctx->m_is_script_thread_active = og_thread != nullptr;
|
||||
|
||||
if constexpr (!std::is_same_v<Ret, void>)
|
||||
{
|
||||
return *reinterpret_cast<Ret*>(stack + top_stack);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace scr_functions
|
||||
{
|
||||
inline script_function set_as_ceo("SAC", "freemode"_J, "2D 04 1D 00 00 5D");
|
||||
inline script_function set_freemode_session_active("SFSA", "freemode"_J, "2D 00 02 00 00 75 5D ? ? ? 50");
|
||||
inline script_function save_to_datafile("STD", "fm_race_creator"_J, "2D 01 03 00 00 71 2C");
|
||||
inline script_function load_from_datafile("LFD", "fm_race_creator"_J, "2D 03 0C 00 00 71 2C");
|
||||
inline script_function reset_session_data("RSD", "main_persistent"_J, "2D 02 7D 00 00");
|
||||
inline script_function add_clan_logo_to_vehicle("ACLTV", "main_persistent"_J, "2D 02 04 00 00 5D ? ? ? 61");
|
||||
inline script_function vehicle_cannot_accept_clan_logo("CVACL", "main_persistent"_J, "2D 01 03 00 00 2C 01 00 A1 06 ? 04");
|
||||
}
|
||||
}
|
@ -109,7 +109,7 @@ namespace big
|
||||
}},
|
||||
{"COPY VEHICLE",
|
||||
[this] {
|
||||
Vehicle v = persist_car_service::clone_ped_car(PLAYER::PLAYER_PED_ID(), m_handle);
|
||||
Vehicle v = persist_car_service::clone_ped_car(VEHICLE::GET_PED_IN_VEHICLE_SEAT(m_handle, -1, 0), m_handle);
|
||||
script::get_current()->yield();
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), v, -1);
|
||||
}},
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "script/tlsContext.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "script/tlsContext.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -37,7 +37,7 @@ namespace big
|
||||
}
|
||||
|
||||
char* storage = new char[0x50000];
|
||||
scr_functions::save_to_datafile.static_call({(uint64_t)storage});
|
||||
scr_functions::save_to_datafile.call<void>((uint64_t)storage);
|
||||
delete[] storage;
|
||||
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("fm_race_creator"_J);
|
||||
@ -77,7 +77,9 @@ namespace big
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
scr_functions::load_from_datafile.static_call({1, true, false, 0});
|
||||
int load_stage = 0; // Will be incremented at the end of each case in the function
|
||||
int ugc_language = NETWORK::UGC_GET_CONTENT_LANGUAGE(0);
|
||||
scr_functions::load_from_datafile.call<bool>(&load_stage, ugc_language, false);
|
||||
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("fm_race_creator"_J);
|
||||
file_stream.close();
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "base/CObject.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "util/misc.hpp"
|
||||
#include "util/vehicle.hpp"
|
||||
#include "util/pools.hpp"
|
||||
@ -327,9 +328,11 @@ namespace big
|
||||
|
||||
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, vehicle_json[dash_color_key]);
|
||||
|
||||
const BOOL have_clan_logo = vehicle_json[clan_logo_key];
|
||||
if (have_clan_logo)
|
||||
vehicle_helper::add_clan_logo_to_vehicle(vehicle, ped);
|
||||
const BOOL needs_clan_logo = vehicle_json[clan_logo_key];
|
||||
if (needs_clan_logo)
|
||||
{
|
||||
scr_functions::add_clan_logo_to_vehicle.call<bool>(&vehicle, NETWORK::NETWORK_GET_PLAYER_INDEX_FROM_PED(ped));
|
||||
}
|
||||
|
||||
VEHICLE::SET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle, vehicle_json[headlight_color_key]);
|
||||
}
|
||||
|
@ -6,23 +6,6 @@
|
||||
|
||||
namespace big
|
||||
{
|
||||
void vehicle_helper::add_clan_logo_to_vehicle(Vehicle vehicle, Ped ped)
|
||||
{
|
||||
rage::fvector3 x, y, z;
|
||||
float scale;
|
||||
Hash modelHash = ENTITY::GET_ENTITY_MODEL(vehicle);
|
||||
if (GetVehicleInfoForClanLogo(modelHash, x, y, z, scale))
|
||||
{
|
||||
int alpha = 200;
|
||||
if (modelHash == VEHICLE_WINDSOR || modelHash == VEHICLE_COMET4)
|
||||
alpha = 255;
|
||||
|
||||
GRAPHICS::ADD_VEHICLE_CREW_EMBLEM(vehicle, ped, ENTITY::GET_ENTITY_BONE_INDEX_BY_NAME(vehicle, "chassis_dummy"), x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, scale, 0, alpha);
|
||||
if (y.z >= 0.0f)
|
||||
GRAPHICS::ADD_VEHICLE_CREW_EMBLEM(vehicle, ped, ENTITY::GET_ENTITY_BONE_INDEX_BY_NAME(vehicle, "chassis_dummy"), x.x * -1.0f, x.y, x.z, y.x * -1.0f, y.y, y.z, z.x * -1.0f, z.y * -1.0f, z.z, scale, 1, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
const char* vehicle_helper::get_mod_slot_name(Hash model, Vehicle vehicle, int mod_slot)
|
||||
{
|
||||
switch (mod_slot)
|
||||
|
@ -10,6 +10,5 @@ namespace big
|
||||
static bool check_mod_blacklist(Hash model, int mod_slot, int mod);
|
||||
static const char* get_mod_slot_name(Hash model, Vehicle vehicle, int mod_slot);
|
||||
static const char* get_mod_name(Hash model, Vehicle vehicle, int mod_slot, int mod, int mod_count);
|
||||
static void add_clan_logo_to_vehicle(Vehicle vehicle, Ped ped);
|
||||
};
|
||||
}
|
||||
|
@ -244,16 +244,15 @@ 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("GUI_TAB_CREATOR"_T.data(), "CREATOR_CANNOT_START"_T.data());
|
||||
return;
|
||||
}
|
||||
|
||||
if (MISC::GET_NUMBER_OF_FREE_STACKS_OF_THIS_SIZE(60500) == 0)
|
||||
if (MISC::GET_NUMBER_OF_FREE_STACKS_OF_THIS_SIZE(62500) == 0)
|
||||
{
|
||||
g_notification_service.push_warning("Creator", "No free stacks for MISSION stack size");
|
||||
g_notification_service.push_warning("GUI_TAB_CREATOR"_T.data(), "CREATOR_NO_FREE_STACKS"_T.data());
|
||||
}
|
||||
|
||||
|
||||
while (!SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED(hash))
|
||||
{
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH(hash);
|
||||
@ -264,7 +263,7 @@ namespace big::scripts
|
||||
*scr_globals::mission_creator_exited.as<bool*>() = false;
|
||||
*scr_globals::mission_creator_radar_follows_camera.as<bool*>() = true;
|
||||
|
||||
if (SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH(hash, 60500))
|
||||
if (SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH(hash, 62500))
|
||||
{
|
||||
g.m_mission_creator_thread = gta_util::find_script_thread(hash);
|
||||
}
|
||||
|
@ -8,13 +8,13 @@
|
||||
#include "pointers.hpp"
|
||||
#include "rage/rlSessionByGamerTaskResult.hpp"
|
||||
#include "script.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "services/api/api_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "thread_pool.hpp"
|
||||
#include "util/globals.hpp"
|
||||
#include "util/misc.hpp"
|
||||
#include "script_function.hpp"
|
||||
|
||||
#include <network/Network.hpp>
|
||||
#include <network/snConnectToPeerTask.hpp>
|
||||
@ -26,11 +26,6 @@ namespace big::session
|
||||
{
|
||||
inline bool join_type(eSessionType session)
|
||||
{
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH("pausemenu_multiplayer"_J);
|
||||
|
||||
while (!SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED("pausemenu_multiplayer"_J))
|
||||
script::get_current()->yield();
|
||||
|
||||
*scr_globals::sctv_spectator.as<int*>() = (session == eSessionType::SC_TV ? 1 : 0); // If SCTV then enable spectator mode
|
||||
|
||||
if (session == eSessionType::LEAVE_ONLINE)
|
||||
@ -52,7 +47,7 @@ namespace big::session
|
||||
*scr_globals::transition_state.as<eTransitionState*>() = eTransitionState::TRANSITION_STATE_RETURN_TO_SINGLEPLAYER;
|
||||
}
|
||||
|
||||
scr_functions::reset_session_data({true, true});
|
||||
scr_functions::reset_session_data.call<void>(true, true);
|
||||
*scr_globals::session3.as<int*>() = 0;
|
||||
*scr_globals::session4.as<int*>() = 1;
|
||||
*scr_globals::session5.as<int*>() = 32;
|
||||
@ -64,7 +59,6 @@ namespace big::session
|
||||
*scr_globals::session.as<int*>() = 0;
|
||||
}
|
||||
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("pausemenu_multiplayer"_J);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "vehicle.hpp"
|
||||
#include "pools.hpp"
|
||||
#include "script_function.hpp"
|
||||
|
||||
namespace big::vehicle
|
||||
{
|
||||
@ -459,7 +460,7 @@ namespace big::vehicle
|
||||
|
||||
if (owned_mods[MOD_HAS_CLAN_LOGO] != 0)
|
||||
{
|
||||
vehicle_helper::add_clan_logo_to_vehicle(vehicle, self::ped);
|
||||
scr_functions::add_clan_logo_to_vehicle.call<bool>(&vehicle, self::id);
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
|
@ -54,10 +54,6 @@ namespace big
|
||||
DLC::ON_ENTER_SP();
|
||||
});
|
||||
|
||||
components::button("START_LS_CUSTOMS"_T, [] {
|
||||
g.vehicle.ls_customs = true;
|
||||
});
|
||||
|
||||
components::button("SKIP_CUTSCENE"_T, [] {
|
||||
CUTSCENE::STOP_CUTSCENE_IMMEDIATELY();
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ namespace big
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::player_command_button<"killengine">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"cloneplayercar">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"burstwheels">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"smashwindows">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"blacktint">(g_player_service->get_selected(), {});
|
||||
|
@ -105,8 +105,6 @@ namespace big
|
||||
components::command_float_input<"superheroflyinitiallaunch">();
|
||||
});
|
||||
|
||||
ImGui::Checkbox("DANCE_MODE"_T.data(), &g.self.dance_mode);
|
||||
|
||||
components::command_checkbox<"orbitaldrone">();
|
||||
components::options_modal("VIEW_SELF_ORBITAL_DRONE"_T.data(), [] {
|
||||
ImGui::Separator();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/vehicle_helper/vehicle_helper.hpp"
|
||||
#include "script_function.hpp"
|
||||
#include "util/vehicle.hpp"
|
||||
#include "views/view.hpp"
|
||||
|
||||
@ -24,6 +24,8 @@ namespace big
|
||||
|
||||
static int selected_slot = -1;
|
||||
static bool is_bennys = false;
|
||||
static bool has_clan_logo = false;
|
||||
static bool vehicle_cannot_accept_clan_logo = false;
|
||||
static int front_wheel_stock_mod = -1;
|
||||
static int rear_wheel_stock_mod = -1;
|
||||
|
||||
@ -77,7 +79,9 @@ namespace big
|
||||
tmp_mod_display_names[MOD_WINDOW_TINT].insert(lsc_window_tint_types.begin(), lsc_window_tint_types.end());
|
||||
tmp_mod_display_names[MOD_WHEEL_TYPE].insert(lsc_wheel_styles.begin(), lsc_wheel_styles.end());
|
||||
|
||||
is_bennys = owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_BENNYS_ORIGINAL || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_BENNYS_BESPOKE || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_OPEN_WHEEL || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_STREET || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_TRACK;
|
||||
is_bennys = owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_BENNYS_ORIGINAL || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_BENNYS_BESPOKE || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_OPEN_WHEEL || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_STREET || owned_mods[MOD_WHEEL_TYPE] == WHEEL_TYPE_TRACK;
|
||||
has_clan_logo = GRAPHICS::DOES_VEHICLE_HAVE_CREW_EMBLEM(player_vehicle, 0);
|
||||
vehicle_cannot_accept_clan_logo = scr_functions::vehicle_cannot_accept_clan_logo.call<bool>(player_vehicle);
|
||||
|
||||
for (int slot = MOD_SPOILERS; slot <= MOD_LIGHTBAR; slot++)
|
||||
{
|
||||
@ -260,26 +264,21 @@ namespace big
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(player_vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
|
||||
});
|
||||
}
|
||||
rage::fvector3 blank;
|
||||
float scale;
|
||||
if (GetVehicleInfoForClanLogo(model, blank, blank, blank, scale))
|
||||
if (!vehicle_cannot_accept_clan_logo)
|
||||
{
|
||||
auto has_clan_logo = (bool*)&owned_mods[MOD_HAS_CLAN_LOGO];
|
||||
if (ImGui::Checkbox("CLAN_LOGO"_T.data(), has_clan_logo))
|
||||
if (ImGui::Checkbox("CLAN_LOGO"_T.data(), &has_clan_logo))
|
||||
{
|
||||
if (*has_clan_logo)
|
||||
{
|
||||
g_fiber_pool->queue_job([] {
|
||||
vehicle_helper::add_clan_logo_to_vehicle(player_vehicle, self::ped);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fiber_pool->queue_job([] {
|
||||
g_fiber_pool->queue_job([] {
|
||||
if (has_clan_logo)
|
||||
{
|
||||
scr_functions::add_clan_logo_to_vehicle.call<bool>(&player_vehicle, self::id);
|
||||
}
|
||||
else
|
||||
{
|
||||
GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 0);
|
||||
GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user