Refactor Debug Threads & Expose More Functions (#3408)

- Added a search box for the script names in Debug -> Threads.
- Added `is_session_started` and `force_script_on_player` functions to the Lua network class.
- Added `is_active` and `start_launcher_script` functions to the Lua script class.
- Moved `view_stat_editor.cpp` to `src/views/network` from `src/views/settings`.
- Added a help text for directly editing the sliders in outfit editor.
This commit is contained in:
Arthur 2024-07-23 16:34:30 +03:00 committed by GitHub
parent f66f96295b
commit f6a6f5dd86
7 changed files with 820 additions and 699 deletions

View File

@ -2,7 +2,7 @@
Table containing helper functions for network related features. Table containing helper functions for network related features.
## Functions (15) ## Functions (17)
### `trigger_script_event(bitset, _args)` ### `trigger_script_event(bitset, _args)`
@ -17,6 +17,15 @@ Call trigger_script_event (TSE)
network.trigger_script_event(bitset, _args) network.trigger_script_event(bitset, _args)
``` ```
### `is_session_started()`
Returns true if the local player is in a multiplayer session.
**Example Usage:**
```lua
network.is_session_started()
```
### `give_pickup_rewards(player, reward)` ### `give_pickup_rewards(player, reward)`
Give the given pickup reward to the given player. Give the given pickup reward to the given player.
@ -134,7 +143,7 @@ string = network.get_flagged_modder_reason(player_idx)
### `force_script_host(script_name)` ### `force_script_host(script_name)`
Try to force ourself to be host for the given GTA Script. Try to force ourself to be host for the given GTA Script. Needs to be called in the fiber pool or a loop.
- **Parameters:** - **Parameters:**
- `script_name` (string): Name of the script - `script_name` (string): Name of the script
@ -144,6 +153,20 @@ Try to force ourself to be host for the given GTA Script.
network.force_script_host(script_name) network.force_script_host(script_name)
``` ```
### `force_script_on_player(player_idx, script_name, instance_id)`
Forces the given GTA script to be started on a player. Needs to be called in the fiber pool or a loop.
- **Parameters:**
- `player_idx` (integer): Index of the player.
- `script_name` (string): Name of the script.
- `instance_id` (integer): Instance ID of the script.
**Example Usage:**
```lua
network.force_script_on_player(script_name)
```
### `send_chat_message(msg, team_only)` ### `send_chat_message(msg, team_only)`
Sends a message to the in game chat. Sends a message to the in game chat.

View File

@ -2,7 +2,7 @@
Table containing helper functions related to gta scripts. Table containing helper functions related to gta scripts.
## Functions (5) ## Functions (7)
### `register_looped(name, func)` ### `register_looped(name, func)`
@ -67,6 +67,18 @@ script.run_in_fiber(function (script)
end) end)
``` ```
### `is_active(script_name)`
Returns true if the specified script is currently active/running.
- **Parameters:**
- `script_name` (string): The name of the script.
**Example Usage:**
```lua
local is_freemode_active = script.is_active("freemode")
```
### `execute_as_script(script_name, func)` ### `execute_as_script(script_name, func)`
- **Parameters:** - **Parameters:**
@ -108,4 +120,18 @@ Calls a function from the specified script.
**Example Usage:** **Example Usage:**
```lua ```lua
script.call_function("Collect Collectible", "freemode", "2D 05 33 00 00", 0, {17, 0, 1, 1, 0}) 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.
- **Parameters:**
- `name` (string): The name of the script.
**Example Usage:**
```lua
script.run_in_fiber(function()
script.start_launcher_script("am_hunt_the_beast")
end)
``` ```

View File

@ -40,6 +40,15 @@ namespace lua::network
big::g_pointers->m_gta.m_trigger_script_event(1, actual_args.data(), actual_args.size(), bitset, args[0]); big::g_pointers->m_gta.m_trigger_script_event(1, actual_args.data(), actual_args.size(), bitset, args[0]);
} }
// Lua API: Function
// Table: network
// Name: is_session_started
// Returns true if the local player is in a multiplayer session.
static bool is_session_started()
{
return *big::g_pointers->m_gta.m_is_session_started;
}
// Lua API: Function // Lua API: Function
// Table: network // Table: network
// Name: give_pickup_rewards // Name: give_pickup_rewards
@ -171,13 +180,26 @@ namespace lua::network
// Lua API: Function // Lua API: Function
// Table: network // Table: network
// Name: force_script_host // Name: force_script_host
// Param: script_name: string: Name of the script // Param: script_name: string: Name of the script.
// Try to force ourself to be host for the given GTA Script. // Try to force ourself to be host for the given GTA Script. Needs to be called in the fiber pool or a loop.
static void force_script_host(const std::string& script_name) static void force_script_host(const std::string& script_name)
{ {
big::scripts::force_host(rage::joaat(script_name)); big::scripts::force_host(rage::joaat(script_name));
} }
// Lua API: function
// Table: script
// Name: force_script_on_player
// Param: player_idx: integer: Index of the player.
// Param: script_name: string: Name of the script.
// Param: script_name: integer: Instance ID of the script.
// Forces the given GTA script to be started on a player. Needs to be called in the fiber pool or a loop.
static void force_script_on_player(int player_idx, const std::string& script_name, int instance_id)
{
if (auto player = big::g_player_service->get_by_id(player_idx))
big::scripts::force_script_on_player(player, rage::joaat(script_name), instance_id);
}
// Lua API: Function // Lua API: Function
// Table: network // Table: network
// Name: send_chat_message // Name: send_chat_message
@ -335,6 +357,7 @@ namespace lua::network
auto ns = state["network"].get_or_create<sol::table>(); auto ns = state["network"].get_or_create<sol::table>();
ns["trigger_script_event"] = trigger_script_event; ns["trigger_script_event"] = trigger_script_event;
ns["is_session_started"] = is_session_started;
ns["give_pickup_rewards"] = give_pickup_rewards; ns["give_pickup_rewards"] = give_pickup_rewards;
ns["set_player_coords"] = set_player_coords; ns["set_player_coords"] = set_player_coords;
ns["set_all_player_coords"] = set_all_player_coords; ns["set_all_player_coords"] = set_all_player_coords;
@ -345,6 +368,7 @@ namespace lua::network
ns["is_player_friend"] = is_player_friend; ns["is_player_friend"] = is_player_friend;
ns["get_flagged_modder_reason"] = get_flagged_modder_reason; ns["get_flagged_modder_reason"] = get_flagged_modder_reason;
ns["force_script_host"] = force_script_host; ns["force_script_host"] = force_script_host;
ns["force_script_on_player"] = force_script_on_player;
ns["send_chat_message"] = send_chat_message; ns["send_chat_message"] = send_chat_message;
ns["send_chat_message_to_player"] = send_chat_message_to_player; ns["send_chat_message_to_player"] = send_chat_message_to_player;
ns["get_player_rank"] = get_player_rank; ns["get_player_rank"] = get_player_rank;

View File

@ -7,6 +7,7 @@
#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"
#include "util/scripts.hpp"
namespace lua::script namespace lua::script
{ {
@ -155,6 +156,23 @@ namespace lua::script
module->m_registered_scripts.push_back(std::move(lua_script)); module->m_registered_scripts.push_back(std::move(lua_script));
} }
// Lua API: function
// Table: script
// Name: is_active
// Param: script_name: string: The name of the script.
// Returns true if the specified script is currently active/running.
// **Example Usage:**
// ```lua
// local is_freemode_active = script.is_active("freemode")
// ```
static bool is_active(const std::string& script_name)
{
if (auto script = big::gta_util::find_script_thread(rage::joaat(script_name)))
return true;
return false;
}
// Lua API: function // Lua API: function
// Table: script // Table: script
// Name: execute_as_script // Name: execute_as_script
@ -175,9 +193,9 @@ namespace lua::script
// Param _patch: table: The bytes to be written into the script's bytecode. // Param _patch: table: The bytes to be written into the script's bytecode.
// Adds a patch for the specified script. // Adds a patch for the specified script.
// **Example Usage:** // **Example Usage:**
//```lua // ```lua
//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})
//``` // ```
static void add_patch(const std::string& script_name, const std::string& name, const std::string& pattern, int offset, sol::table _patch) static void add_patch(const std::string& script_name, const std::string& name, const std::string& pattern, int offset, sol::table _patch)
{ {
auto patch = convert_sequence<uint8_t>(_patch); auto patch = convert_sequence<uint8_t>(_patch);
@ -197,9 +215,9 @@ namespace lua::script
// Param _args: table: The arguments to pass to the script function. // Param _args: table: The arguments to pass to the script function.
// Calls a function from the specified script. // Calls a function from the specified script.
// **Example Usage:** // **Example Usage:**
//```lua // ```lua
//script.call_function("Collect Collectible", "freemode", "2D 05 33 00 00", 0, {17, 0, 1, 1, 0}) // 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) 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); auto args = convert_sequence<uint64_t>(_args);
@ -208,14 +226,32 @@ namespace lua::script
script_function(args); script_function(args);
} }
// Lua API: function
// Table: script
// Name: start_launcher_script
// Param: script_name: string: The name of the script.
// Tries to start a launcher script. Needs to be called in the fiber pool or a loop.
// **Example Usage:**
// ```lua
// script.run_in_fiber(function()
// script.start_launcher_script("am_hunt_the_beast")
// end)
// ```
static void start_launcher_script(const std::string& script_name)
{
big::scripts::start_launcher_script(rage::joaat(script_name));
}
void bind(sol::state& state) void bind(sol::state& state)
{ {
auto ns = state["script"].get_or_create<sol::table>(); auto ns = state["script"].get_or_create<sol::table>();
ns["register_looped"] = register_looped; ns["register_looped"] = register_looped;
ns["run_in_fiber"] = run_in_fiber; ns["run_in_fiber"] = run_in_fiber;
ns["execute_as_script"] = execute_as_script; ns["is_active"] = is_active;
ns["add_patch"] = add_patch; ns["execute_as_script"] = execute_as_script;
ns["call_function"] = call_function; 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"); auto usertype = state.new_usertype<script_util>("script_util");

View File

@ -12,7 +12,7 @@ static rage::scrThread* selected_thread;
static int selected_stack_size = 128; static int selected_stack_size = 128;
static int free_stacks = -1; static int free_stacks = -1;
static const char* selected_stack_size_str = "MULTIPLAYER_MISSION"; static const char* selected_stack_size_str = "MULTIPLAYER_MISSION";
static const char* selected_script = "<SELECT>"; static const char* selected_script = "";
static std::chrono::high_resolution_clock::time_point last_stack_update_time{}; static std::chrono::high_resolution_clock::time_point last_stack_update_time{};
@ -37,7 +37,7 @@ namespace big
return; return;
} }
components::small_text("VIEW_DEBUG_THREADS"_T); ImGui::SeparatorText("VIEW_DEBUG_THREADS"_T.data());
if (ImGui::BeginCombo("VIEW_DEBUG_THREADS_THREAD"_T.data(), selected_thread ? selected_thread->m_name : "VIEW_DEBUG_THREADS_SELECTED_NONE"_T.data())) if (ImGui::BeginCombo("VIEW_DEBUG_THREADS_THREAD"_T.data(), selected_thread ? selected_thread->m_name : "VIEW_DEBUG_THREADS_SELECTED_NONE"_T.data()))
{ {
@ -72,6 +72,13 @@ namespace big
if (selected_thread) if (selected_thread)
{ {
static const std::string thread_states = std::string("VIEW_DEBUG_THREADS_STATE_0"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_1"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_2"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_3"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_4"_T.data()) + '\0';
ImGui::Combo("VIEW_DEBUG_THREADS_STATE"_T.data(), (int*)&selected_thread->m_context.m_state, thread_states.c_str());
auto net_handler = reinterpret_cast<CGameScriptHandlerNetComponent*>(selected_thread->m_net_component); auto net_handler = reinterpret_cast<CGameScriptHandlerNetComponent*>(selected_thread->m_net_component);
if (net_handler) if (net_handler)
@ -83,36 +90,28 @@ namespace big
if (!net_handler->is_local_player_host()) if (!net_handler->is_local_player_host())
{ {
components::button("VIEW_DEBUG_THREADS_TAKE_CONTROL"_T, [net_handler] { ImGui::SameLine();
net_handler->send_host_migration_event(g_player_service->get_self()->get_net_game_player()); if (ImGui::SmallButton("VIEW_DEBUG_THREADS_TAKE_CONTROL"_T.data()))
}); {
g_fiber_pool->queue_job([net_handler] {
net_handler->send_host_migration_event(g_player_service->get_self()->get_net_game_player());
});
}
} }
} }
} }
static const std::string thread_states = std::string("VIEW_DEBUG_THREADS_STATE_0"_T.data()) + '\0' ImGui::Text(std::format("{}: 0x{:X}", "VIEW_DEBUG_THREADS_SCRIPT_POINTER"_T, (DWORD64)selected_thread).c_str());
+ std::string("VIEW_DEBUG_THREADS_STATE_1"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_2"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_3"_T.data()) + '\0'
+ std::string("VIEW_DEBUG_THREADS_STATE_4"_T.data()) + '\0';
ImGui::Combo("VIEW_DEBUG_THREADS_STATE"_T.data(), (int*)&selected_thread->m_context.m_state, thread_states.c_str());
//Script Pointer
ImGui::Text(std::format("{}: ", "VIEW_DEBUG_THREADS_SCRIPT_POINTER"_T).c_str());
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button(std::format("0x{:X}", (DWORD64)selected_thread).c_str())) if (ImGui::SmallButton(std::format("{}##script_ptr", "COPY"_T).c_str()))
ImGui::SetClipboardText(std::format("0x{:X}", (DWORD64)selected_thread).c_str()); ImGui::SetClipboardText(std::format("0x{:X}", (DWORD64)selected_thread).c_str());
//Stack Pointer ImGui::Text(std::format("{}: 0x{:X}", "VIEW_DEBUG_THREADS_STACK_POINTER"_T, (DWORD64)selected_thread->m_stack).c_str());
ImGui::Text(std::format("{}: ", "VIEW_DEBUG_THREADS_STACK_POINTER"_T).c_str());
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button(std::format("0x{:X}", (DWORD64)selected_thread->m_stack).c_str())) if (ImGui::SmallButton(std::format("{}##stack_ptr", "COPY"_T).c_str()))
ImGui::SetClipboardText(std::format("0x{:X}", (DWORD64)selected_thread->m_stack).c_str()); ImGui::SetClipboardText(std::format("0x{:X}", (DWORD64)selected_thread->m_stack).c_str());
ImGui::SameLine(); ImGui::Text(std::format("{}: {}", "VIEW_DEBUG_THREADS_INTERNAL_STACK_POINTER"_T, selected_thread->m_context.m_stack_pointer).c_str());
ImGui::Text(std::format("{}: {} {}: {}", ImGui::Text(std::format("{}: 0x{:X}", "VIEW_DEBUG_THREADS_INSTRUCTION_POINTER"_T, selected_thread->m_context.m_instruction_pointer).c_str());
"VIEW_DEBUG_THREADS_INTERNAL_STACK_POINTER"_T, selected_thread->m_context.m_stack_pointer, ImGui::Text(std::format("{}: {}", "VIEW_DEBUG_THREADS_STACK_SIZE"_T, selected_thread->m_context.m_stack_size).c_str());
"VIEW_DEBUG_THREADS_STACK_SIZE"_T, selected_thread->m_context.m_stack_size)
.c_str());
//Instruction Pointer
ImGui::Text(std::format("{}: 0x{:X}","VIEW_DEBUG_THREADS_INSTRUCTION_POINTER"_T, selected_thread->m_context.m_instruction_pointer).c_str());
if (selected_thread->m_context.m_state == rage::eThreadState::killed) if (selected_thread->m_context.m_state == rage::eThreadState::killed)
{ {
@ -130,22 +129,11 @@ namespace big
} }
} }
components::small_text("VIEW_DEBUG_THREADS_NEW"_T); ImGui::SeparatorText("VIEW_DEBUG_THREADS_NEW"_T.data());
if (ImGui::BeginCombo("VIEW_DEBUG_THREADS_SCRIPT"_T.data(), selected_script)) static std::string search_script = "";
{
for (auto script : all_script_names)
{
if (ImGui::Selectable(script, script == selected_script))
{
selected_script = script;
}
if (script == selected_script) components::input_text_with_hint("VIEW_DEBUG_THREADS_SCRIPT"_T, "SEARCH"_T, search_script, ImGuiInputTextFlags_None);
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("VIEW_DEBUG_THREADS_STACK_SIZE"_T.data(), selected_stack_size_str)) if (ImGui::BeginCombo("VIEW_DEBUG_THREADS_STACK_SIZE"_T.data(), selected_stack_size_str))
{ {
@ -167,6 +155,28 @@ namespace big
ImGui::EndCombo(); ImGui::EndCombo();
} }
if (ImGui::BeginListBox("##scripts"))
{
std::string lower_search = search_script;
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), ::tolower);
for (auto& script : all_script_names)
{
std::string lower_script = script;
std::transform(lower_script.begin(), lower_script.end(), lower_script.begin(), ::tolower);
if (lower_script.find(lower_search) != std::string::npos)
{
if (ImGui::Selectable(script, selected_script == script))
{
selected_script = script;
search_script = script;
}
}
}
ImGui::EndListBox();
}
ImGui::Text(std::format("{}: {}", "VIEW_DEBUG_THREADS_FREE_STACKS"_T, free_stacks).c_str()); ImGui::Text(std::format("{}: {}", "VIEW_DEBUG_THREADS_FREE_STACKS"_T, free_stacks).c_str());
components::button("SETTINGS_NOTIFY_GTA_THREADS_START"_T, [] { components::button("SETTINGS_NOTIFY_GTA_THREADS_START"_T, [] {

View File

@ -31,6 +31,8 @@ namespace big
} }
}); });
components::sub_title("VIEW_OUTFIT_EDITOR_TIP"_T);
components::button("OUTFIT_RANDOM_COMPONENT"_T, [] { components::button("OUTFIT_RANDOM_COMPONENT"_T, [] {
ped::set_ped_random_component_variation(self::ped); ped::set_ped_random_component_variation(self::ped);
}); });