Add Return Value Support for Script Functions (#3479)
Some checks are pending
Nightly Build / Build Nightly (push) Blocked by required conditions
Nightly Build / Recreate Release (push) Blocked by required conditions
Nightly Build / Check Recent Commit (push) Successful in 20s

* 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:
Arthur 2024-08-06 15:46:48 +03:00 committed by GitHub
parent 013b463536
commit 09b91ca6d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 606 additions and 3549 deletions

View File

@ -63,6 +63,18 @@ Rips the current memory address and returns a new pointer object.
pointer = pointer:rip(offset) 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()` ### `get_byte()`
Retrieves the value stored at the memory address as the specified type. 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() 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)` ### `set_byte(value)`
Sets the value at the memory address to the specified value of the given type. Sets the value at the memory address to the specified value of the given type.

View 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 }
})
```

View File

@ -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}) 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)` ### `start_launcher_script(script_name)`
Tries to start a launcher script. Needs to be called in the fiber pool or a loop. Tries to start a launcher script. Needs to be called in the fiber pool or a loop.

View File

@ -54,7 +54,6 @@ namespace big
{ {
looped::self_wanted(); looped::self_wanted();
looped::self_hud(); looped::self_hud();
looped::self_dance_mode();
looped::self_persist_outfit(); looped::self_persist_outfit();
script::get_current()->yield(); 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() void backend::rainbowpaint_loop()
{ {
LOG(INFO) << "Starting script: Rainbow paint"; LOG(INFO) << "Starting script: Rainbow Paint";
while (g_running) while (g_running)
{ {

View File

@ -13,7 +13,6 @@ namespace big
static void vehicles_loop(); static void vehicles_loop();
static void misc_loop(); static void misc_loop();
static void remote_loop(); static void remote_loop();
static void lscustoms_loop();
static void rainbowpaint_loop(); static void rainbowpaint_loop();
static void disable_control_action_loop(); static void disable_control_action_loop();
static void world_loop(); static void world_loop();

View File

@ -9,7 +9,7 @@ namespace big
virtual void execute(player_ptr player, const command_arguments& _args, const std::shared_ptr<command_context> ctx) override 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);
} }
}; };

View 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);
}

View File

@ -27,7 +27,6 @@ namespace big
static void self_wanted(); static void self_wanted();
static void self_hud(); static void self_hud();
static void self_dance_mode();
static void self_persist_outfit(); static void self_persist_outfit();
static void session_pop_multiplier_areas(); static void session_pop_multiplier_areas();
@ -48,7 +47,6 @@ namespace big
static void vehicle_auto_drive(); static void vehicle_auto_drive();
static void vehicle_allow_all_weapons(); static void vehicle_allow_all_weapons();
static void vehicle_boost_behavior(); static void vehicle_boost_behavior();
static void vehicle_ls_customs();
static void vehicle_rainbow_paint(); static void vehicle_rainbow_paint();
static void weapons_tp_gun(); static void weapons_tp_gun();

View File

@ -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, {});
}
}
}

View File

@ -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), {});
}
}
}

View File

@ -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, "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, "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({"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, "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({"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({"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({"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({"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, "carmod_shop2", "2D 00 B8 00 00", 5, {0x2E, 0x00, 0x00}, &g.vehicle.ls_customs});
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", "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({"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) for (auto& entry : *g_pointers->m_gta.m_script_program_table)
{ {

View File

@ -38,8 +38,6 @@ namespace big::scr_globals
static inline const script_global spawn_global(2696212); static inline const script_global spawn_global(2696212);
static inline const script_global dance_state(1943520);
static inline const script_global transaction_overlimit(20913); static inline const script_global transaction_overlimit(20913);
static inline const script_global stats(2359296); static inline const script_global stats(2359296);
@ -107,15 +105,4 @@ namespace big::scr_locals
// func_\d+\((&.Local_\d+(, )?){9}\); // func_\d+\((&.Local_\d+(, )?){9}\);
inline static script_local mobile(19139); 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"
}
} }

View File

@ -80,9 +80,6 @@ namespace big
rage::scrThread* m_hunt_the_beast_thread = nullptr; 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; rage::scrThread* m_mission_creator_thread = nullptr;
struct script_block_opts struct script_block_opts
@ -114,8 +111,7 @@ namespace big
bool enabled = false; bool enabled = false;
} cmd_executor{}; } cmd_executor{};
rage::scrThread* m_modshop_thread = nullptr; bool in_script_vm = false;
bool in_script_vm = false;
struct debug 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) 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{}; } hud{};
// do not save below entries
bool dance_mode = false;
struct super_hero_fly 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) NLOHMANN_DEFINE_TYPE_INTRUSIVE(super_hero_fly, gradual, explosions, auto_land, charge, ptfx, fly_speed, initial_launch)
} super_hero_fly{}; } 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{}; } self{};
@ -806,7 +800,6 @@ namespace big
bool instant_brake = false; bool instant_brake = false;
bool infinite_veh_ammo = false; bool infinite_veh_ammo = false;
bool block_homing = true; bool block_homing = true;
bool ls_customs = false; // don't save this to disk
bool seatbelt = false; bool seatbelt = false;
bool turn_signals = false; bool turn_signals = false;
bool vehicle_jump = false; bool vehicle_jump = false;

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,6 @@
#include <network/CNetGamePlayer.hpp> #include <network/CNetGamePlayer.hpp>
#include <script/globals/GPBD_FM_3.hpp> #include <script/globals/GPBD_FM_3.hpp>
#include <script/globals/GlobalPlayerBD.hpp> #include <script/globals/GlobalPlayerBD.hpp>
#include <script/CGameScriptHandlerNetComponent.hpp>
namespace big namespace big
{ {

View File

@ -17,15 +17,9 @@ namespace big
if (thread == g.m_hunt_the_beast_thread) if (thread == g.m_hunt_the_beast_thread)
g.m_hunt_the_beast_thread = nullptr; 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) if (thread == g.m_mission_creator_thread)
g.m_mission_creator_thread = nullptr; g.m_mission_creator_thread = nullptr;
if (thread == g.m_modshop_thread)
g.m_modshop_thread = nullptr;
return result; return result;
} }
} }

View File

@ -625,12 +625,14 @@ namespace lua::memory
pointer_ut["add"] = &pointer::add; pointer_ut["add"] = &pointer::add;
pointer_ut["sub"] = &pointer::sub; pointer_ut["sub"] = &pointer::sub;
pointer_ut["rip"] = &pointer::rip; pointer_ut["rip"] = &pointer::rip;
pointer_ut["get_int"] = &pointer::get<int32_t>;
pointer_ut["get_byte"] = &pointer::get<uint8_t>; pointer_ut["get_byte"] = &pointer::get<uint8_t>;
pointer_ut["get_word"] = &pointer::get<uint16_t>; pointer_ut["get_word"] = &pointer::get<uint16_t>;
pointer_ut["get_dword"] = &pointer::get<uint32_t>; pointer_ut["get_dword"] = &pointer::get<uint32_t>;
pointer_ut["get_qword"] = &pointer::get<uint64_t>; pointer_ut["get_qword"] = &pointer::get<uint64_t>;
pointer_ut["get_float"] = &pointer::get<float>; pointer_ut["get_float"] = &pointer::get<float>;
pointer_ut["get_string"] = &pointer::get_string; 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_byte"] = &pointer::set<uint8_t>;
pointer_ut["set_word"] = &pointer::set<uint16_t>; pointer_ut["set_word"] = &pointer::set<uint16_t>;
pointer_ut["set_dword"] = &pointer::set<uint32_t>; pointer_ut["set_dword"] = &pointer::set<uint32_t>;

View File

@ -137,6 +137,10 @@ namespace lua::memory
{ {
return type_info_t::double_; return type_info_t::double_;
} }
else if (s.contains("vector3"))
{
return type_info_t::vector3_;
}
else else
{ {
return type_info_t::integer_; return type_info_t::integer_;

View 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);
}
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "script_function.hpp"
namespace lua::scr_function
{
void bind(sol::state& state);
}

View File

@ -3,7 +3,6 @@
#include "lua/lua_manager.hpp" #include "lua/lua_manager.hpp"
#include "gta_util.hpp" #include "gta_util.hpp"
#include "script_function.hpp"
#include "lua/bindings/network.hpp" #include "lua/bindings/network.hpp"
#include "memory/pattern.hpp" #include "memory/pattern.hpp"
#include "services/script_patcher/script_patcher_service.hpp" #include "services/script_patcher/script_patcher_service.hpp"
@ -205,27 +204,6 @@ namespace lua::script
big::g_script_patcher_service->on_script_load(program); 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 // Lua API: function
// Table: script // Table: script
// Name: start_launcher_script // Name: start_launcher_script
@ -250,7 +228,6 @@ namespace lua::script
ns["is_active"] = is_active; ns["is_active"] = is_active;
ns["execute_as_script"] = execute_as_script; ns["execute_as_script"] = execute_as_script;
ns["add_patch"] = add_patch; ns["add_patch"] = add_patch;
ns["call_function"] = call_function;
ns["start_launcher_script"] = start_launcher_script; ns["start_launcher_script"] = start_launcher_script;
auto usertype = state.new_usertype<script_util>("script_util"); auto usertype = state.new_usertype<script_util>("script_util");

View File

@ -10,6 +10,7 @@ namespace lua::memory
integer_, integer_,
ptr_, ptr_,
float_, float_,
double_ double_,
vector3_
}; };
} }

View File

@ -13,6 +13,7 @@
#include "bindings/native.hpp" #include "bindings/native.hpp"
#include "bindings/network.hpp" #include "bindings/network.hpp"
#include "bindings/script.hpp" #include "bindings/script.hpp"
#include "bindings/scr_function.hpp"
#include "bindings/self.hpp" #include "bindings/self.hpp"
#include "bindings/stats.hpp" #include "bindings/stats.hpp"
#include "bindings/tunables.hpp" #include "bindings/tunables.hpp"
@ -298,6 +299,7 @@ namespace big
lua::log::bind(m_state); lua::log::bind(m_state);
lua::globals::bind(m_state); lua::globals::bind(m_state);
lua::script::bind(m_state); lua::script::bind(m_state);
lua::scr_function::bind(m_state);
lua::native::bind(m_state); lua::native::bind(m_state);
lua::memory::bind(m_state); lua::memory::bind(m_state);
lua::gui::bind(m_state); lua::gui::bind(m_state);

View File

@ -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::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::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::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::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::disable_control_action_loop, "Disable Controls"));
g_script_mgr.add_script(std::make_unique<script>(&backend::world_loop, "World")); g_script_mgr.add_script(std::make_unique<script>(&backend::world_loop, "World"));

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "script_function.hpp"
namespace big namespace big
{ {

View File

@ -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));
}
}
}
}

View File

@ -73,7 +73,7 @@ namespace big
{ {
if (SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME() == "freemode"_J && g.session.fast_join) 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); src->set_return_value<BOOL>(TRUE);
} }
else else

View File

@ -3,7 +3,6 @@
#include "all_scripts.hpp" #include "all_scripts.hpp"
#include "am_launcher.hpp" #include "am_launcher.hpp"
#include "am_pi_menu.hpp" #include "am_pi_menu.hpp"
#include "carmod_shop.hpp"
#include "creator.hpp" #include "creator.hpp"
#include "freemode.hpp" #include "freemode.hpp"
#include "network_session_host.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::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("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::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::STAT_GET_INT, freemode::STAT_GET_INT);
add_native_detour("freemode"_J, NativeIndex::IS_PLAYER_PLAYING, freemode::IS_PLAYER_PLAYING); add_native_detour("freemode"_J, NativeIndex::IS_PLAYER_PLAYING, freemode::IS_PLAYER_PLAYING);

View File

@ -1,136 +1,30 @@
#include "script_function.hpp" #include "script_function.hpp"
#include "gta_util.hpp"
#include "pointers.hpp"
#include "util/scripts.hpp"
#include <script/scrProgram.hpp>
namespace big 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_name(name),
m_script(script), m_script(script),
m_pattern(pattern), m_pattern(pattern),
m_offset(offset),
m_ip(0) 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); m_ip = *location;
LOG(VERBOSE) << "Found pattern " << m_name << " at " << HEX_TO_UPPER(m_ip) << " in script " << program->m_name;
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;
} }
} else
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)
{ {
call(thread, program, args); LOG(FATAL) << "Failed to find pattern " << m_name << " in script " << program->m_name;
} }
return m_ip;
} }
} }

View File

@ -1,43 +1,74 @@
#pragma once #pragma once
#include "gta/joaat.hpp"
#include "memory/pattern.hpp" #include "gta_util.hpp"
#include "pointers.hpp"
#include "util/scripts.hpp"
#include <script/scrProgram.hpp>
namespace big 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 class script_function
{ {
rage::joaat_t m_script; rage::joaat_t m_script;
const memory::pattern m_pattern; const memory::pattern m_pattern;
int32_t m_offset; uint32_t m_ip;
int32_t m_ip;
std::string m_name; std::string m_name;
public: public:
script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern, int32_t offset); script_function(const std::string& name, const rage::joaat_t script, const std::string& pattern);
void populate_ip(); uint32_t get_ip(rage::scrProgram* program);
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 template<typename Arg>
void static_call(const std::vector<uint64_t>& args); 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);
}
void operator()(const std::vector<uint64_t>& args); 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 namespace scr_functions
{ {
static inline script_function join_ceo("JC", "freemode"_J, "2D 04 1D 00 00 5D", 0); inline script_function set_as_ceo("SAC", "freemode"_J, "2D 04 1D 00 00 5D");
static inline script_function set_freemode_session_active("SFSA", "freemode"_J, "2D 00 02 00 00 75 5D ? ? ? 50", 0); inline script_function set_freemode_session_active("SFSA", "freemode"_J, "2D 00 02 00 00 75 5D ? ? ? 50");
static inline script_function dance_loop("DL", "am_mp_nightclub"_J, "2D 00 14 00 00 4F ? ? 47 ? ? 5D ? ? ? 56", 0); inline script_function save_to_datafile("STD", "fm_race_creator"_J, "2D 01 03 00 00 71 2C");
static inline script_function init_nightclub_script("INS", "am_mp_nightclub"_J, "2D 00 11 00 00 4F", 0); 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");
static inline script_function save_to_datafile("STD", "fm_race_creator"_J, "2D 01 03 00 00 71 2C", 0); inline script_function add_clan_logo_to_vehicle("ACLTV", "main_persistent"_J, "2D 02 04 00 00 5D ? ? ? 61");
static inline script_function load_from_datafile("LFD", "fm_race_creator"_J, "2D 04 0D 00 00 71 2C", 0); inline script_function vehicle_cannot_accept_clan_logo("CVACL", "main_persistent"_J, "2D 01 03 00 00 2C 01 00 A1 06 ? 04");
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);
} }
} }

View File

@ -109,7 +109,7 @@ namespace big
}}, }},
{"COPY VEHICLE", {"COPY VEHICLE",
[this] { [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(); script::get_current()->yield();
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), v, -1); PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), v, -1);
}}, }},

View File

@ -4,8 +4,8 @@
#include "natives.hpp" #include "natives.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "script.hpp" #include "script.hpp"
#include "script/tlsContext.hpp"
#include "script_function.hpp" #include "script_function.hpp"
#include "script/tlsContext.hpp"
namespace big namespace big
{ {
@ -37,7 +37,7 @@ namespace big
} }
char* storage = new char[0x50000]; 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; delete[] storage;
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("fm_race_creator"_J); SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("fm_race_creator"_J);
@ -77,7 +77,9 @@ namespace big
script::get_current()->yield(); 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); SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("fm_race_creator"_J);
file_stream.close(); file_stream.close();

View File

@ -2,6 +2,7 @@
#include "base/CObject.hpp" #include "base/CObject.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "script_function.hpp"
#include "util/misc.hpp" #include "util/misc.hpp"
#include "util/vehicle.hpp" #include "util/vehicle.hpp"
#include "util/pools.hpp" #include "util/pools.hpp"
@ -327,9 +328,11 @@ namespace big
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, vehicle_json[dash_color_key]); VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, vehicle_json[dash_color_key]);
const BOOL have_clan_logo = vehicle_json[clan_logo_key]; const BOOL needs_clan_logo = vehicle_json[clan_logo_key];
if (have_clan_logo) if (needs_clan_logo)
vehicle_helper::add_clan_logo_to_vehicle(vehicle, ped); {
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]); VEHICLE::SET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle, vehicle_json[headlight_color_key]);
} }

View File

@ -6,23 +6,6 @@
namespace big 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) const char* vehicle_helper::get_mod_slot_name(Hash model, Vehicle vehicle, int mod_slot)
{ {
switch (mod_slot) switch (mod_slot)

View File

@ -10,6 +10,5 @@ namespace big
static bool check_mod_blacklist(Hash model, int mod_slot, int mod); 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_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 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);
}; };
} }

View File

@ -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()) 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; 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)) while (!SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED(hash))
{ {
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH(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_exited.as<bool*>() = false;
*scr_globals::mission_creator_radar_follows_camera.as<bool*>() = true; *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); g.m_mission_creator_thread = gta_util::find_script_thread(hash);
} }

View File

@ -8,13 +8,13 @@
#include "pointers.hpp" #include "pointers.hpp"
#include "rage/rlSessionByGamerTaskResult.hpp" #include "rage/rlSessionByGamerTaskResult.hpp"
#include "script.hpp" #include "script.hpp"
#include "script_function.hpp"
#include "services/api/api_service.hpp" #include "services/api/api_service.hpp"
#include "services/player_database/player_database_service.hpp" #include "services/player_database/player_database_service.hpp"
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "thread_pool.hpp" #include "thread_pool.hpp"
#include "util/globals.hpp" #include "util/globals.hpp"
#include "util/misc.hpp" #include "util/misc.hpp"
#include "script_function.hpp"
#include <network/Network.hpp> #include <network/Network.hpp>
#include <network/snConnectToPeerTask.hpp> #include <network/snConnectToPeerTask.hpp>
@ -26,11 +26,6 @@ namespace big::session
{ {
inline bool join_type(eSessionType 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 *scr_globals::sctv_spectator.as<int*>() = (session == eSessionType::SC_TV ? 1 : 0); // If SCTV then enable spectator mode
if (session == eSessionType::LEAVE_ONLINE) 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_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::session3.as<int*>() = 0;
*scr_globals::session4.as<int*>() = 1; *scr_globals::session4.as<int*>() = 1;
*scr_globals::session5.as<int*>() = 32; *scr_globals::session5.as<int*>() = 32;
@ -64,7 +59,6 @@ namespace big::session
*scr_globals::session.as<int*>() = 0; *scr_globals::session.as<int*>() = 0;
} }
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED("pausemenu_multiplayer"_J);
return true; return true;
} }

View File

@ -1,5 +1,6 @@
#include "vehicle.hpp" #include "vehicle.hpp"
#include "pools.hpp" #include "pools.hpp"
#include "script_function.hpp"
namespace big::vehicle namespace big::vehicle
{ {
@ -459,7 +460,7 @@ namespace big::vehicle
if (owned_mods[MOD_HAS_CLAN_LOGO] != 0) 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; return vehicle;

View File

@ -54,10 +54,6 @@ namespace big
DLC::ON_ENTER_SP(); DLC::ON_ENTER_SP();
}); });
components::button("START_LS_CUSTOMS"_T, [] {
g.vehicle.ls_customs = true;
});
components::button("SKIP_CUTSCENE"_T, [] { components::button("SKIP_CUTSCENE"_T, [] {
CUTSCENE::STOP_CUTSCENE_IMMEDIATELY(); CUTSCENE::STOP_CUTSCENE_IMMEDIATELY();
}); });

View File

@ -20,6 +20,7 @@ namespace big
ImGui::BeginGroup(); ImGui::BeginGroup();
components::player_command_button<"killengine">(g_player_service->get_selected(), {}); 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<"burstwheels">(g_player_service->get_selected(), {});
components::player_command_button<"smashwindows">(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(), {}); components::player_command_button<"blacktint">(g_player_service->get_selected(), {});

View File

@ -105,8 +105,6 @@ namespace big
components::command_float_input<"superheroflyinitiallaunch">(); components::command_float_input<"superheroflyinitiallaunch">();
}); });
ImGui::Checkbox("DANCE_MODE"_T.data(), &g.self.dance_mode);
components::command_checkbox<"orbitaldrone">(); components::command_checkbox<"orbitaldrone">();
components::options_modal("VIEW_SELF_ORBITAL_DRONE"_T.data(), [] { components::options_modal("VIEW_SELF_ORBITAL_DRONE"_T.data(), [] {
ImGui::Separator(); ImGui::Separator();

View File

@ -2,7 +2,7 @@
#include "fiber_pool.hpp" #include "fiber_pool.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "script.hpp" #include "script.hpp"
#include "services/vehicle_helper/vehicle_helper.hpp" #include "script_function.hpp"
#include "util/vehicle.hpp" #include "util/vehicle.hpp"
#include "views/view.hpp" #include "views/view.hpp"
@ -24,6 +24,8 @@ namespace big
static int selected_slot = -1; static int selected_slot = -1;
static bool is_bennys = false; 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 front_wheel_stock_mod = -1;
static int rear_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_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()); 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++) 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]); VEHICLE::TOGGLE_VEHICLE_MOD(player_vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
}); });
} }
rage::fvector3 blank; if (!vehicle_cannot_accept_clan_logo)
float scale;
if (GetVehicleInfoForClanLogo(model, blank, blank, blank, scale))
{ {
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([] {
{ if (has_clan_logo)
g_fiber_pool->queue_job([] { {
vehicle_helper::add_clan_logo_to_vehicle(player_vehicle, self::ped); scr_functions::add_clan_logo_to_vehicle.call<bool>(&player_vehicle, self::id);
}); }
} else
else {
{
g_fiber_pool->queue_job([] {
GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 0); GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 0);
GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 1); GRAPHICS::REMOVE_VEHICLE_CREW_EMBLEM(player_vehicle, 1);
}); }
} });
} }
} }