Tunables service fix and theme changes (#1507)
This commit is contained in:
@ -130,7 +130,7 @@ namespace big
|
||||
tabs::NETWORK,
|
||||
{
|
||||
"GUI_TAB_NETWORK",
|
||||
view::session,
|
||||
view::network,
|
||||
{
|
||||
{tabs::SPOOFING, {"GUI_TAB_SPOOFING", view::spoofing}},
|
||||
{tabs::MISSIONS, {"GUI_TAB_MISSIONS", view::missions}},
|
||||
|
@ -51,12 +51,13 @@ namespace big
|
||||
bool block_join = false;
|
||||
int block_join_reason = 1;
|
||||
bool is_modder = false;
|
||||
bool notify_online = false;
|
||||
bool notify_online = false;
|
||||
std::unordered_set<int> infractions;
|
||||
std::string notes = "";
|
||||
std::optional<CommandAccessLevel> command_access_level = std::nullopt;
|
||||
PlayerOnlineStatus online_state = PlayerOnlineStatus::UNKNOWN;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, name, rockstar_id, block_join, block_join_reason, is_modder, notify_online, infractions, command_access_level)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, name, rockstar_id, block_join, block_join_reason, is_modder, notify_online, infractions, notes, command_access_level)
|
||||
};
|
||||
|
||||
};
|
||||
|
404
src/services/script_connection/script_connection.cpp
Normal file
404
src/services/script_connection/script_connection.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
#include "script_connection.hpp"
|
||||
|
||||
#include "gta_util.hpp"
|
||||
#include "hooking.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
#include <script/globals/GPBD_FM_3.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool script_connection::does_remote_script_exist()
|
||||
{
|
||||
return NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(m_target->get()->id(), m_script_name.data(), -1);
|
||||
}
|
||||
|
||||
bool script_connection::start_script_on_local()
|
||||
{
|
||||
while (!SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED(m_script_hash))
|
||||
{
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH(m_script_hash);
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
auto program = gta_util::find_script_program(m_script_hash);
|
||||
|
||||
int count = program->m_local_count;
|
||||
program->m_local_count = 2;
|
||||
int id = SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH(m_script_hash, DEFAULT_STACK_SIZE);
|
||||
program->m_local_count = count;
|
||||
|
||||
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED(m_script_hash);
|
||||
m_thread = gta_util::find_script_thread_by_id(id);
|
||||
|
||||
if (!m_thread)
|
||||
return false;
|
||||
|
||||
m_thread->m_context.m_state = rage::eThreadState::unk_3;
|
||||
return true;
|
||||
}
|
||||
|
||||
void script_connection::start_script_on_remote()
|
||||
{
|
||||
if (!m_target)
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Starting " << m_script_name << " using am_launcher";
|
||||
|
||||
scripts::start_launcher_script(scripts::launcher_index_from_hash(m_script_hash));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Starting " << m_script_name << " using TSEs";
|
||||
|
||||
const size_t arg_count = 25;
|
||||
int64_t args[arg_count] = {(int64_t)eRemoteEvent::StartScriptBegin, (int64_t)self::id};
|
||||
|
||||
args[2] = scripts::launcher_index_from_hash(m_script_hash);
|
||||
strcpy((char*)&args[2 + 3], "0");
|
||||
args[2 + 16] = -1;
|
||||
args[2 + 17] = 1337;
|
||||
args[24] = scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[m_target->get()->id()].ScriptEventReplayProtectionCounter;
|
||||
|
||||
g_pointers->m_gta.m_trigger_script_event(1, args, arg_count, 1 << m_target->get()->id());
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const size_t arg_count_2 = 25;
|
||||
int64_t args_2[arg_count_2] = {(int64_t)eRemoteEvent::StartScriptProceed, (int64_t)self::id};
|
||||
args_2[2 + 17] = 1337;
|
||||
g_pointers->m_gta.m_trigger_script_event(1, args_2, arg_count_2, 1 << m_target->get()->id());
|
||||
|
||||
script::get_current()->yield(20ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool script_connection::populate_instance_id()
|
||||
{
|
||||
for (int i = 0; i < 0x100; i++)
|
||||
{
|
||||
if (NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT_ON_SCRIPT(m_target->get()->id(), m_script_name.data(), i))
|
||||
{
|
||||
m_instance_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m_instance_id != -1;
|
||||
}
|
||||
|
||||
bool script_connection::set_script_as_networked()
|
||||
{
|
||||
gta_util::execute_as_script(m_thread, [this] {
|
||||
if (auto hook = g_hooking->m_handler_hooks[(CGameScriptHandler*)m_thread->m_handler].get())
|
||||
{
|
||||
hook->disable();
|
||||
g_hooking->m_handler_hooks.erase((CGameScriptHandler*)m_thread->m_handler);
|
||||
}
|
||||
|
||||
NETWORK::NETWORK_SET_THIS_SCRIPT_IS_NETWORK_SCRIPT(32, true, m_instance_id);
|
||||
});
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
int status = 0;
|
||||
gta_util::execute_as_script(m_thread, [&status] {
|
||||
status = NETWORK::NETWORK_GET_SCRIPT_STATUS();
|
||||
});
|
||||
|
||||
if (status == 2)
|
||||
return true;
|
||||
|
||||
if (status > 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
script::get_current()->yield(50ms);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void script_connection::setup_broadcast_data()
|
||||
{
|
||||
auto locals = gta_util::find_script_program(m_script_hash)->m_local_data;
|
||||
|
||||
if (m_host_broadcast_size)
|
||||
{
|
||||
m_host_broadcast_data = new uint64_t[m_host_broadcast_size];
|
||||
|
||||
if (m_host_broadcast_default_data_address.has_value())
|
||||
memcpy(m_host_broadcast_data, &locals[m_host_broadcast_default_data_address.value()], m_host_broadcast_size * sizeof(uint64_t));
|
||||
else
|
||||
memset(m_host_broadcast_data, 0, m_host_broadcast_size * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
if (m_player_broadcast_data)
|
||||
{
|
||||
m_player_broadcast_data = new uint64_t[m_player_broadcast_size];
|
||||
|
||||
if (m_player_broadcast_default_data_address.has_value())
|
||||
{
|
||||
memcpy(m_player_broadcast_data, &locals[m_player_broadcast_default_data_address.value()], m_player_broadcast_size * sizeof(uint64_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(m_player_broadcast_data, 0, m_player_broadcast_size * sizeof(uint64_t));
|
||||
m_player_broadcast_data[0] = 32;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_broadcast_setup_callback)
|
||||
m_broadcast_setup_callback(m_thread, m_host_broadcast_data, m_player_broadcast_data);
|
||||
}
|
||||
|
||||
void script_connection::register_broadcast_data()
|
||||
{
|
||||
gta_util::execute_as_script(m_thread, [this] {
|
||||
if (m_host_broadcast_size)
|
||||
NETWORK::NETWORK_REGISTER_HOST_BROADCAST_VARIABLES((int*)m_host_broadcast_data, m_host_broadcast_size, 0);
|
||||
|
||||
if (m_player_broadcast_size)
|
||||
NETWORK::NETWORK_REGISTER_PLAYER_BROADCAST_VARIABLES((int*)m_player_broadcast_data, m_player_broadcast_size, 0);
|
||||
});
|
||||
}
|
||||
|
||||
bool script_connection::force_host_of_script()
|
||||
{
|
||||
if (m_thread && m_thread->m_net_component)
|
||||
{
|
||||
for (int i = 0; !m_thread->m_net_component->is_local_player_host(); i++)
|
||||
{
|
||||
if (i > 200)
|
||||
return false;
|
||||
|
||||
((CGameScriptHandlerNetComponent*)m_thread->m_net_component)
|
||||
->send_host_migration_event(g_player_service->get_self()->get_net_game_player());
|
||||
script::get_current()->yield(10ms);
|
||||
|
||||
if (!m_thread->m_stack || !m_thread->m_net_component)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_thread->m_net_component->block_host_migration(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool script_connection::wait_for_host_broadcast_data()
|
||||
{
|
||||
for (int i = 0; i < 3600; i++)
|
||||
{
|
||||
bool received = false;
|
||||
gta_util::execute_as_script(m_thread, [&received] {
|
||||
received = NETWORK::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA();
|
||||
});
|
||||
|
||||
if (received)
|
||||
return true;
|
||||
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool script_connection::wait_for_connection_to_remote()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
bool is_a_participant = false;
|
||||
gta_util::execute_as_script(m_thread, [&is_a_participant, this] {
|
||||
is_a_participant = NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT(m_target->get()->id());
|
||||
});
|
||||
|
||||
if (is_a_participant)
|
||||
return true;
|
||||
|
||||
script::get_current()->yield(25ms);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool script_connection::start_impl()
|
||||
{
|
||||
auto need_to_create = !m_target || !populate_instance_id();
|
||||
|
||||
if (need_to_create && m_no_remote_start)
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Script must be started on remote, but script starting is disabled";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!start_script_on_local())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Failed to start script locally";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_script_as_networked())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Failed to set script as networked";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
setup_broadcast_data();
|
||||
register_broadcast_data();
|
||||
|
||||
if (!need_to_create && (!m_target || !m_target->get()->is_valid() || !wait_for_connection_to_remote()))
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Remote no longer a participant";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_wait_for_host_broadcast_data && !wait_for_host_broadcast_data())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Failed to receive host broadcast data";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!force_host_of_script())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Failed to get script host";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (need_to_create)
|
||||
start_script_on_remote();
|
||||
|
||||
if (need_to_create && m_target && !wait_for_connection_to_remote())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(FATAL) << "Failed to connect to remote";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_broadcast_modify_callback)
|
||||
m_broadcast_modify_callback(m_thread, m_host_broadcast_data, m_player_broadcast_data);
|
||||
|
||||
m_startup_done = true;
|
||||
m_startup_complete_time = std::chrono::system_clock::now();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
script_connection::script_connection(const std::string& script_name, std::optional<player_ptr> target) :
|
||||
m_script_name(script_name),
|
||||
m_script_hash(rage::joaat(script_name)),
|
||||
m_target(target)
|
||||
{
|
||||
}
|
||||
|
||||
void script_connection::start()
|
||||
{
|
||||
if (m_startup_done && m_thread && m_broadcast_modify_callback)
|
||||
m_broadcast_modify_callback(m_thread, m_host_broadcast_data, m_player_broadcast_data);
|
||||
|
||||
if (m_startup_done || m_startup_failed)
|
||||
return;
|
||||
|
||||
if (!start_impl())
|
||||
m_startup_failed = true;
|
||||
}
|
||||
|
||||
void script_connection::cleanup()
|
||||
{
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->kill();
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
if (m_host_broadcast_data)
|
||||
{
|
||||
delete[] m_host_broadcast_data;
|
||||
m_host_broadcast_data = nullptr;
|
||||
}
|
||||
|
||||
if (m_player_broadcast_data)
|
||||
{
|
||||
delete[] m_player_broadcast_data;
|
||||
m_player_broadcast_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool script_connection::should_cleanup()
|
||||
{
|
||||
if (m_startup_failed)
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Startup has failed, cleaning up";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_startup_done && (!m_thread || m_thread->m_stack == nullptr || m_thread->m_context.m_state == rage::eThreadState::killed))
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Local thread has been terminated, cleaning up";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_startup_done && m_target && !m_target->get()->is_valid())
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Target has left, cleaning up";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (m_target && m_target->get()->is_valid())
|
||||
{
|
||||
bool is_a_participant = false;
|
||||
|
||||
gta_util::execute_as_script(m_thread, [&is_a_participant, this] {
|
||||
is_a_participant = NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT(m_target->get()->id());
|
||||
});
|
||||
|
||||
if (!is_a_participant)
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Target no longer a participant, cleaning up";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool might_cleanup = m_quick_cleanup || MISC::GET_NUMBER_OF_FREE_STACKS_OF_THIS_SIZE(DEFAULT_STACK_SIZE) < 5;
|
||||
|
||||
if (might_cleanup && m_startup_complete_time.has_value()
|
||||
&& std::chrono::system_clock::now() - m_startup_complete_time.value() > 5s)
|
||||
{
|
||||
if (m_debug_logging)
|
||||
LOG(VERBOSE) << "Cleaning up";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
75
src/services/script_connection/script_connection.hpp
Normal file
75
src/services/script_connection/script_connection.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include "services/players/player_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
constexpr int DEFAULT_STACK_SIZE = 1424;
|
||||
|
||||
class script_connection
|
||||
{
|
||||
std::string m_script_name;
|
||||
rage::joaat_t m_script_hash;
|
||||
std::optional<player_ptr> m_target;
|
||||
int m_instance_id = -1;
|
||||
rage::scrThread* m_thread = nullptr;
|
||||
bool m_startup_done = false;
|
||||
bool m_startup_failed = false;
|
||||
int m_host_broadcast_size = 0;
|
||||
int m_player_broadcast_size = 0;
|
||||
bool m_debug_logging = false;
|
||||
bool m_wait_for_host_broadcast_data = false;
|
||||
bool m_no_remote_start = false;
|
||||
bool m_quick_cleanup = false;
|
||||
std::optional<int> m_host_broadcast_default_data_address = std::nullopt;
|
||||
std::optional<int> m_player_broadcast_default_data_address = std::nullopt;
|
||||
|
||||
std::function<void(rage::scrThread*, uint64_t*, uint64_t*)> m_broadcast_setup_callback{};
|
||||
std::function<void(rage::scrThread*, uint64_t*, uint64_t*)> m_broadcast_modify_callback{};
|
||||
|
||||
std::uint64_t* m_host_broadcast_data = nullptr;
|
||||
std::uint64_t* m_player_broadcast_data = nullptr;
|
||||
std::optional<std::chrono::system_clock::time_point> m_startup_complete_time = std::nullopt;
|
||||
|
||||
bool does_remote_script_exist();
|
||||
bool start_script_on_local();
|
||||
void start_script_on_remote();
|
||||
bool populate_instance_id();
|
||||
bool set_script_as_networked();
|
||||
void setup_broadcast_data();
|
||||
void register_broadcast_data();
|
||||
bool force_host_of_script();
|
||||
bool wait_for_host_broadcast_data();
|
||||
bool wait_for_connection_to_remote();
|
||||
|
||||
bool start_impl();
|
||||
|
||||
public:
|
||||
script_connection(const std::string& script_name, std::optional<player_ptr> target = std::nullopt);
|
||||
void start();
|
||||
void cleanup();
|
||||
bool should_cleanup();
|
||||
|
||||
// clang-format off
|
||||
|
||||
inline rage::joaat_t get_script_hash() { return m_script_hash; }
|
||||
inline std::optional<player_ptr> get_target() { return m_target; }
|
||||
inline rage::scrThread* get_script_thread() { return m_thread; }
|
||||
|
||||
inline void set_host_broadcast_size(int size) { m_host_broadcast_size = size; }
|
||||
inline void set_player_broadcast_size(int size) { m_player_broadcast_size = size; }
|
||||
inline void set_debug_logging(bool enabled) { m_debug_logging = enabled; }
|
||||
inline void set_wait_for_host_broadcast_data(bool enabled) { m_wait_for_host_broadcast_data = enabled; }
|
||||
inline void set_no_remote_start(bool enabled) { m_no_remote_start = enabled; }
|
||||
inline void set_quick_cleanup(bool enabled) { m_quick_cleanup = enabled; }
|
||||
inline void set_host_broadcast_default_data_address(int data_address) { m_host_broadcast_default_data_address = data_address; }
|
||||
inline void set_player_broadcast_default_data_address(int data_address) { m_player_broadcast_default_data_address = data_address; }
|
||||
|
||||
// thread, host_broadcast_data, player_broadcast_data
|
||||
inline void set_broadcast_setup_callback(std::function<void(rage::scrThread*, uint64_t*, uint64_t*)> cb) { m_broadcast_setup_callback = std::move(cb); }
|
||||
inline void set_broadcast_modify_callback(std::function<void(rage::scrThread*, uint64_t*, uint64_t*)> cb) { m_broadcast_modify_callback = std::move(cb); }
|
||||
|
||||
inline void invalidate_script_thread() { m_thread = nullptr; }
|
||||
|
||||
// clang-format on
|
||||
};
|
||||
}
|
52
src/services/script_connection/script_connection_service.cpp
Normal file
52
src/services/script_connection/script_connection_service.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "script_connection_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
script_connection* script_connection_service::get_connection(const std::string& script_name, std::optional<player_ptr> target)
|
||||
{
|
||||
auto hash = rage::joaat(script_name);
|
||||
|
||||
for (auto& cxn : m_script_connections)
|
||||
if (cxn->get_script_hash() == hash
|
||||
&& ((!target && !cxn->get_target())
|
||||
|| (target && cxn->get_target() && target->get()->id() == cxn->get_target()->get()->id())))
|
||||
return cxn.get();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
script_connection_service::script_connection_service()
|
||||
{
|
||||
g_script_connection_service = this;
|
||||
}
|
||||
|
||||
script_connection_service::~script_connection_service()
|
||||
{
|
||||
g_script_connection_service = nullptr;
|
||||
}
|
||||
|
||||
script_connection* script_connection_service::create_connection(const std::string& script_name, std::optional<player_ptr> target)
|
||||
{
|
||||
if (auto cxn = get_connection(script_name, target))
|
||||
return cxn;
|
||||
|
||||
auto cxn = std::make_unique<script_connection>(script_name, target);
|
||||
auto ret = cxn.get();
|
||||
m_script_connections.push_back(std::move(cxn));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void script_connection_service::on_tick()
|
||||
{
|
||||
std::erase_if(m_script_connections, [](auto& cxn) {
|
||||
if (cxn.get()->should_cleanup())
|
||||
{
|
||||
cxn.get()->cleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
20
src/services/script_connection/script_connection_service.hpp
Normal file
20
src/services/script_connection/script_connection_service.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "script_connection.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class script_connection_service
|
||||
{
|
||||
std::vector<std::unique_ptr<script_connection>> m_script_connections;
|
||||
script_connection* get_connection(const std::string& script_name, std::optional<player_ptr> target);
|
||||
|
||||
public:
|
||||
script_connection_service();
|
||||
~script_connection_service();
|
||||
|
||||
script_connection* create_connection(const std::string& script_name, std::optional<player_ptr> target);
|
||||
void on_tick();
|
||||
};
|
||||
|
||||
inline script_connection_service* g_script_connection_service;
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/script_connection/script_connection_service.hpp" // for the stack size
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include "thread_pool.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
@ -60,9 +61,9 @@ namespace big
|
||||
|
||||
if (SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED(RAGE_JOAAT("tuneables_processing")))
|
||||
{
|
||||
std::uint64_t args[] = {6, 27, 1}; // TODO: check args
|
||||
std::uint64_t args[] = {6, 27}; // TODO: check args
|
||||
|
||||
int id = SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS(RAGE_JOAAT("tuneables_processing"), (Any*)args, sizeof(args) / 8, 5050);
|
||||
int id = SYSTEM::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS(RAGE_JOAAT("tuneables_processing"), (Any*)args, sizeof(args) / 8, DEFAULT_STACK_SIZE);
|
||||
|
||||
if (!id)
|
||||
{
|
||||
@ -85,6 +86,7 @@ namespace big
|
||||
if (m_tunables.size() == 0)
|
||||
{
|
||||
LOG(FATAL) << "Failed to cache tunables";
|
||||
g_script_patcher_service->update();
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user