mirror of
https://github.com/YimMenu/YimMenuV2.git
synced 2026-10-10 03:43:15 +08:00
feat(debug): Add Scripts Tab (#243)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
template<typename T>
|
||||
bool Bitfield(const char* name, T* param)
|
||||
{
|
||||
bool ret = false;
|
||||
ImGuiDataType type;
|
||||
size_t size = sizeof(T);
|
||||
std::string format;
|
||||
if (size == 1)
|
||||
{
|
||||
type = ImGuiDataType_U8;
|
||||
format = "%02X";
|
||||
}
|
||||
if (size == 2)
|
||||
{
|
||||
type = ImGuiDataType_U16;
|
||||
format = "%04X";
|
||||
}
|
||||
if (size == 4)
|
||||
{
|
||||
type = ImGuiDataType_U32;
|
||||
format = "%08X";
|
||||
}
|
||||
if (size == 8)
|
||||
{
|
||||
type = ImGuiDataType_U64;
|
||||
format = "%p";
|
||||
}
|
||||
|
||||
if (ImGui::InputScalar(name, type, param, NULL, NULL, format.c_str(), ImGuiInputTextFlags_CharsHexadecimal))
|
||||
ret = true;
|
||||
size_t bits = (size * 8) - 1ULL;
|
||||
for (size_t i = bits; i < SIZE_MAX; i--)
|
||||
{
|
||||
if (i % 4 == 0)
|
||||
ImGui::BeginGroup();
|
||||
if (*param & (1ULL << i))
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32_BLACK_TRANS);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(41, 134, 204, 255));
|
||||
if (ImGui::Button(std::format("1##{}{}", name, i).c_str(), ImVec2(25, 0)))
|
||||
{
|
||||
ret = true;
|
||||
*param ^= (1ULL << i);
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32_BLACK_TRANS);
|
||||
if (ImGui::Button(std::format("0##{}{}", name, i).c_str(), ImVec2(25, 0)))
|
||||
{
|
||||
ret = true;
|
||||
*param ^= (1ULL << i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
ImGui::Text("%i", i);
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
if (i % 16 != 0)
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,12 @@ namespace YimMenu
|
||||
enum class VariableType
|
||||
{
|
||||
INT,
|
||||
FLOAT,
|
||||
INT64,
|
||||
BITSET,
|
||||
BOOL,
|
||||
INT64
|
||||
FLOAT,
|
||||
VECTOR,
|
||||
STRING
|
||||
};
|
||||
|
||||
struct VariableAppendage
|
||||
|
||||
@@ -3,12 +3,20 @@
|
||||
#include "core/memory/ModuleMgr.hpp"
|
||||
#include "core/backend/ScriptMgr.hpp"
|
||||
#include "game/backend/NativeHooks.hpp"
|
||||
#include "game/gta/data/StackSizes.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "types/script/scrProgram.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
struct TUNABLES_LAUNCH_DATA
|
||||
{
|
||||
SCR_INT Context;
|
||||
SCR_INT ContentModifier;
|
||||
};
|
||||
static_assert(sizeof(TUNABLES_LAUNCH_DATA) == 2 * 8);
|
||||
|
||||
static void TunablesWaitHook(rage::scrNativeCallContext* src)
|
||||
{
|
||||
if (Tunables::CachingTunables())
|
||||
@@ -73,9 +81,7 @@ namespace YimMenu
|
||||
|
||||
if (m_CacheFile.UpToDate(ModuleMgr.Get("GTA5_Enhanced.exe"_J)->GetNtHeader()->FileHeader.TimeDateStamp))
|
||||
{
|
||||
LOG(INFO) << "Loading tunables from cache.";
|
||||
m_Loading = true;
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -101,7 +107,7 @@ namespace YimMenu
|
||||
TUNABLES_LAUNCH_DATA args;
|
||||
args.Context = 6; // BASE_GLOBALS
|
||||
args.ContentModifier = 27; // MP_FM_RANDOM
|
||||
if (!BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS("tuneables_processing"_J, &args, sizeof(args) / 8, 1424))
|
||||
if (!BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS("tuneables_processing"_J, &args, SCR_SIZEOF(args), eStackSizes::DEFAULT))
|
||||
{
|
||||
LOG(FATAL) << "Failed to start tuneables_processing. Cannot cache tunables.";
|
||||
return;
|
||||
@@ -186,5 +192,7 @@ namespace YimMenu
|
||||
|
||||
m_Initialized = true;
|
||||
m_Loading = false;
|
||||
|
||||
LOG(INFO) << "Loaded " << m_Tunables.size() << " tunables from cache.";
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,6 @@ namespace YimMenu
|
||||
{
|
||||
constexpr int TUNABLE_BASE_ADDRESS = 0x40001;
|
||||
|
||||
struct TUNABLES_LAUNCH_DATA
|
||||
{
|
||||
alignas(8) int Context;
|
||||
alignas(8) int ContentModifier;
|
||||
};
|
||||
static_assert(sizeof(TUNABLES_LAUNCH_DATA) == 2 * 8);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct TunableSaveStruct
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "GiveVehicleReward.hpp"
|
||||
#include "core/backend/ScriptMgr.hpp"
|
||||
#include "game/backend/Self.hpp"
|
||||
#include "game/gta/data/StackSizes.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "game/gta/ScriptFunction.hpp"
|
||||
@@ -40,7 +41,7 @@ namespace YimMenu
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH("AM_MP_VEHICLE_REWARD"_J);
|
||||
if (SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED("AM_MP_VEHICLE_REWARD"_J))
|
||||
{
|
||||
int id = BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH("AM_MP_VEHICLE_REWARD"_J, 2050);
|
||||
int id = BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH("AM_MP_VEHICLE_REWARD"_J, eStackSizes::FRIEND);
|
||||
m_Thread = Scripts::FindScriptThreadByID(id);
|
||||
if (m_Thread)
|
||||
m_Thread->m_Context.m_State = rage::scrThread::State::PAUSED;
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
#include "game/backend/Self.hpp"
|
||||
#include "game/backend/ScriptPatches.hpp"
|
||||
#include "game/backend/NativeHooks.hpp"
|
||||
#include "game/gta/data/StackSizes.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "game/gta/ScriptLocal.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "types/script/types.hpp"
|
||||
|
||||
namespace YimMenu::Features
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace YimMenu::Features
|
||||
launchData.Type = 7;
|
||||
launchData.Position = Self::GetPed().GetPosition();
|
||||
launchData.Heading = Self::GetPed().GetHeading();
|
||||
if (!BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS("wardrobe_mp"_J, &launchData, sizeof(launchData) / 8, 2324))
|
||||
if (!BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH_AND_ARGS("wardrobe_mp"_J, &launchData, SCR_SIZEOF(launchData), eStackSizes::SHOP))
|
||||
{
|
||||
Notifications::Show("Wardrobe", "Failed to open the wardrobe.", NotificationType::Error);
|
||||
return;
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
#include "Debug.hpp"
|
||||
|
||||
#include "Debug/Misc.hpp"
|
||||
#include "Debug/Globals.hpp"
|
||||
#include "Debug/Locals.hpp"
|
||||
//#include "Debug/Scripts.hpp"
|
||||
#include "Debug/Misc.hpp"
|
||||
|
||||
#include "Debug/Scripts.hpp"
|
||||
#include "game/frontend/items/Items.hpp"
|
||||
|
||||
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
Debug::Debug() :
|
||||
Submenu::Submenu("Debug")
|
||||
{
|
||||
AddCategory(BuildMiscMenu());
|
||||
AddCategory(BuildGlobalsMenu());
|
||||
AddCategory(BuildLocalsMenu());
|
||||
AddCategory(BuildMiscMenu());
|
||||
AddCategory(BuildScriptsMenu());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#include "DrawVariable.hpp"
|
||||
#include "core/frontend/widgets/imgui_bitfield.hpp"
|
||||
#include "types/script/scrVector.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void DrawSavedVariableEdit(const SavedVariableBase& var, void* value)
|
||||
{
|
||||
if (!value)
|
||||
return ImGui::TextDisabled("Invalid");
|
||||
|
||||
switch (var.type)
|
||||
{
|
||||
case VariableType::INT:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputScalar("Value", ImGuiDataType_S32, static_cast<int*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::INT64:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputScalar("Value", ImGuiDataType_S64, static_cast<std::int64_t*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::BITSET:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::Bitfield("Value", static_cast<int*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::BOOL:
|
||||
{
|
||||
ImGui::Checkbox("Value", static_cast<bool*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::FLOAT:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputScalar("Value", ImGuiDataType_Float, static_cast<float*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::VECTOR:
|
||||
{
|
||||
auto vectorPtr = (rage::scrVector*)value;
|
||||
ImGui::PushItemWidth(100.f);
|
||||
ImGui::InputScalar("X", ImGuiDataType_Float, &vectorPtr->x);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("Y", ImGuiDataType_Float, &vectorPtr->y);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("Z", ImGuiDataType_Float, &vectorPtr->z);
|
||||
ImGui::PopItemWidth();
|
||||
break;
|
||||
}
|
||||
case VariableType::STRING:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputText("Value", static_cast<char*>(value), 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSavedVariablePreview(const SavedVariableBase& var, void* value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
ImGui::Selectable("Invalid", false, ImGuiSelectableFlags_Disabled);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (var.type)
|
||||
{
|
||||
case VariableType::INT:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<int*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::INT64:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<std::int64_t*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::BITSET:
|
||||
{
|
||||
std::ostringstream bitset;
|
||||
bitset << HEX(*static_cast<int*>(value));
|
||||
ImGui::Selectable(bitset.str().c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::BOOL:
|
||||
{
|
||||
ImGui::Selectable(*static_cast<bool*>(value) ? "True" : "False", false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::FLOAT:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<float*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::VECTOR:
|
||||
{
|
||||
auto vectorPtr = (rage::scrVector*)value;
|
||||
std::ostringstream vector;
|
||||
vector << "X: " << std::fixed << std::setprecision(2) << vectorPtr->x << " Y: " << vectorPtr->y << " Z: " << vectorPtr->z;
|
||||
ImGui::Selectable(vector.str().c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::STRING:
|
||||
{
|
||||
ImGui::Selectable(static_cast<char*>(value), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSavedVariable(SavedVariableBase& var)
|
||||
{
|
||||
ImGui::SetNextItemWidth(175.0f);
|
||||
ImGui::InputScalar("Index", ImGuiDataType_U32, &var.base);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(100.0f);
|
||||
ImGui::Combo("##var_type", (int*)&var.type, "Int\0Int64\0Bitset\0Bool\0Float\0Vector\0String\0");
|
||||
|
||||
for (int i = 0; i < var.appendages.size(); i++)
|
||||
{
|
||||
auto& item = var.appendages[i];
|
||||
switch (item.type)
|
||||
{
|
||||
case VariableAppendage::Type::OFFSET:
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("At##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.offset);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("Size##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.size);
|
||||
break;
|
||||
case VariableAppendage::Type::PLAYER_ID:
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("Size##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add Offset"))
|
||||
var.appendages.push_back({VariableAppendage::Type::OFFSET, 0LL, 0ULL});
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Add Read Player Id"))
|
||||
var.appendages.push_back({VariableAppendage::Type::PLAYER_ID, 0LL, 0ULL});
|
||||
|
||||
if (var.appendages.size() > 0)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove Offset"))
|
||||
{
|
||||
var.appendages.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear"))
|
||||
{
|
||||
var.base = 0;
|
||||
var.appendages.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,124 +3,7 @@
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
static void DrawSavedVariableEdit(const SavedVariableBase& var, void* value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
ImGui::BeginDisabled();
|
||||
ImGui::Text("Invalid");
|
||||
ImGui::EndDisabled();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (var.type)
|
||||
{
|
||||
case VariableType::INT:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputInt("Value", static_cast<int*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::BOOL:
|
||||
{
|
||||
ImGui::Checkbox("Value", static_cast<bool*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::FLOAT:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputFloat("Value", static_cast<float*>(value));
|
||||
break;
|
||||
}
|
||||
case VariableType::INT64:
|
||||
{
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputScalar("Value", ImGuiDataType_S64, static_cast<std::int64_t*>(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSavedVariablePreview(const SavedVariableBase& var, void* value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
ImGui::Selectable("Invalid", false, ImGuiSelectableFlags_Disabled);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (var.type)
|
||||
{
|
||||
case VariableType::INT:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<int*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::BOOL:
|
||||
{
|
||||
ImGui::Selectable(*static_cast<bool*>(value) ? "True" : "False", false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::FLOAT:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<float*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
case VariableType::INT64:
|
||||
{
|
||||
ImGui::Selectable(std::to_string(*static_cast<std::int64_t*>(value)).c_str(), false, ImGuiSelectableFlags_Disabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSavedVariable(SavedVariableBase& var)
|
||||
{
|
||||
ImGui::SetNextItemWidth(175.0f);
|
||||
ImGui::InputScalar("Index", ImGuiDataType_U32, &var.base);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(100.0f);
|
||||
ImGui::Combo("##var_type", (int*)&var.type, "Int\0Float\0Bool\0Int64\0");
|
||||
|
||||
for (int i = 0; i < var.appendages.size(); i++)
|
||||
{
|
||||
auto& item = var.appendages[i];
|
||||
switch (item.type)
|
||||
{
|
||||
case VariableAppendage::Type::OFFSET:
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("At##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.offset);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("Size##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.size);
|
||||
break;
|
||||
case VariableAppendage::Type::PLAYER_ID:
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputScalar(std::format("Size##{}{}", i, (int)item.type).c_str(), ImGuiDataType_S32, &item.size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add Offset"))
|
||||
var.appendages.push_back({VariableAppendage::Type::OFFSET, 0LL, 0ULL});
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Add Read Player Id"))
|
||||
var.appendages.push_back({VariableAppendage::Type::PLAYER_ID, 0LL, 0ULL});
|
||||
|
||||
if (var.appendages.size() > 0)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove Offset"))
|
||||
{
|
||||
var.appendages.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear"))
|
||||
{
|
||||
var.base = 0;
|
||||
var.appendages.clear();
|
||||
}
|
||||
}
|
||||
extern void DrawSavedVariableEdit(const SavedVariableBase& var, void* value);
|
||||
extern void DrawSavedVariablePreview(const SavedVariableBase& var, void* value);
|
||||
extern void DrawSavedVariable(SavedVariableBase& var);
|
||||
}
|
||||
@@ -1,32 +1,30 @@
|
||||
#include "Globals.hpp"
|
||||
#include "game/backend/SavedVariables.hpp"
|
||||
|
||||
#include "DrawVariable.hpp"
|
||||
|
||||
// TODO: name compares are expensive, but this is way better than the old impl that reads the json file every frame
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
static void SaveGlobal(SavedGlobal& global_obj)
|
||||
static void SaveGlobal(SavedGlobal& globalObj)
|
||||
{
|
||||
for (auto& global : SavedVariables::GetSavedGlobals())
|
||||
{
|
||||
if (global.name == global_obj.name)
|
||||
if (global.name == globalObj.name)
|
||||
{
|
||||
global = global_obj;
|
||||
global = globalObj;
|
||||
SavedVariables::Save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SavedVariables::GetSavedGlobals().push_back(global_obj);
|
||||
SavedVariables::GetSavedGlobals().push_back(globalObj);
|
||||
SavedVariables::Save();
|
||||
}
|
||||
|
||||
static void DeleteGlobal(SavedGlobal& global_obj)
|
||||
static void DeleteGlobal(SavedGlobal& globalObj)
|
||||
{
|
||||
std::erase_if(SavedVariables::GetSavedGlobals(), [&](SavedGlobal& g) {
|
||||
return g.name == global_obj.name;
|
||||
return g.name == globalObj.name;
|
||||
});
|
||||
SavedVariables::Save();
|
||||
}
|
||||
@@ -35,31 +33,31 @@ namespace YimMenu::Submenus
|
||||
{
|
||||
auto globals = std::make_unique<Category>("Globals");
|
||||
|
||||
static bool ensure_vars_loaded = ([] {
|
||||
auto editor = std::make_unique<Group>("Editor");
|
||||
auto saved = std::make_unique<Group>("Saved");
|
||||
|
||||
static bool ensureVarsLoaded = ([] {
|
||||
SavedVariables::Init();
|
||||
return true;
|
||||
})();
|
||||
|
||||
static char global_name[255]{};
|
||||
static char globalName[255]{};
|
||||
static SavedGlobal curGlobal{};
|
||||
|
||||
static SavedGlobal cur_global{};
|
||||
|
||||
auto editor = std::make_unique<Group>("Editor");
|
||||
editor->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
DrawSavedVariable(cur_global);
|
||||
DrawSavedVariableEdit(cur_global, cur_global.Read());
|
||||
DrawSavedVariable(curGlobal);
|
||||
DrawSavedVariableEdit(curGlobal, curGlobal.Read());
|
||||
}));
|
||||
|
||||
auto saved = std::make_unique<Group>("Saved");
|
||||
saved->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
if (ImGui::BeginListBox("##savedglobals", ImVec2(200, 200)))
|
||||
{
|
||||
for (auto& var : SavedVariables::GetSavedGlobals())
|
||||
{
|
||||
if (ImGui::Selectable(var.name.c_str(), var.name == cur_global.name))
|
||||
if (ImGui::Selectable(var.name.c_str(), var.name == curGlobal.name))
|
||||
{
|
||||
cur_global = var;
|
||||
strncpy(global_name, var.name.c_str(), sizeof(global_name));
|
||||
curGlobal = var;
|
||||
strncpy(globalName, var.name.c_str(), sizeof(globalName));
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
@@ -77,19 +75,19 @@ namespace YimMenu::Submenus
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputTextWithHint("##global_name", "Name", global_name, sizeof(global_name));
|
||||
ImGui::InputTextWithHint("##global_name", "Name", globalName, sizeof(globalName));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Save"))
|
||||
{
|
||||
cur_global.name = global_name;
|
||||
SaveGlobal(cur_global);
|
||||
curGlobal.name = globalName;
|
||||
SaveGlobal(curGlobal);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Delete"))
|
||||
{
|
||||
cur_global.name = global_name;
|
||||
DeleteGlobal(cur_global);
|
||||
cur_global = SavedGlobal();
|
||||
curGlobal.name = globalName;
|
||||
DeleteGlobal(curGlobal);
|
||||
curGlobal = SavedGlobal();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
@@ -1,37 +1,30 @@
|
||||
#include "Locals.hpp"
|
||||
|
||||
#include "DrawVariable.hpp"
|
||||
#include "core/filemgr/FileMgr.hpp"
|
||||
#include "game/backend/SavedVariables.hpp"
|
||||
#include "game/backend/Self.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "game/gta/ScriptGlobal.hpp"
|
||||
|
||||
#include "types/rage/atArray.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "types/script/scrThread.hpp"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
static void SaveLocal(SavedLocal& local_obj)
|
||||
static void SaveLocal(SavedLocal& localObj)
|
||||
{
|
||||
for (auto& local : SavedVariables::GetSavedLocals())
|
||||
{
|
||||
if (local.name == local_obj.name && local.script == local_obj.script)
|
||||
if (local.name == localObj.name && local.script == localObj.script)
|
||||
{
|
||||
local = local_obj;
|
||||
local = localObj;
|
||||
SavedVariables::Save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SavedVariables::GetSavedLocals().push_back(local_obj);
|
||||
SavedVariables::GetSavedLocals().push_back(localObj);
|
||||
SavedVariables::Save();
|
||||
}
|
||||
|
||||
static void DeleteLocal(SavedLocal& local_obj)
|
||||
static void DeleteLocal(SavedLocal& localObj)
|
||||
{
|
||||
std::erase_if(SavedVariables::GetSavedLocals(), [&](SavedLocal& g) {
|
||||
return g.name == local_obj.name && g.script == local_obj.script;
|
||||
return g.name == localObj.name && g.script == localObj.script;
|
||||
});
|
||||
SavedVariables::Save();
|
||||
}
|
||||
@@ -40,121 +33,66 @@ namespace YimMenu::Submenus
|
||||
{
|
||||
auto locals = std::make_unique<Category>("Locals");
|
||||
|
||||
static bool ensure_vars_loaded = ([] {
|
||||
auto editor = std::make_unique<Group>("Editor");
|
||||
auto saved = std::make_unique<Group>("Saved");
|
||||
|
||||
static bool ensureVarsLoaded = ([] {
|
||||
SavedVariables::Init();
|
||||
return true;
|
||||
})();
|
||||
|
||||
static char local_name[255]{};
|
||||
static char scriptName[255]{};
|
||||
static char localName[255]{};
|
||||
static SavedLocal curLocal{};
|
||||
static rage::scrThread* curThread = nullptr;
|
||||
|
||||
static SavedLocal cur_local{};
|
||||
|
||||
static rage::scrThread* cur_thread = nullptr;
|
||||
static const char* cur_script_name = nullptr;
|
||||
static std::uint32_t cur_script_hash = 0;
|
||||
|
||||
auto script = std::make_unique<Group>("Script");
|
||||
|
||||
script->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
// TODO: pointless code reduplication
|
||||
if (!Pointers.ScriptThreads || Pointers.ScriptThreads->size() == 0)
|
||||
{
|
||||
cur_thread = nullptr;
|
||||
ImGui::TextDisabled("None");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(225.0f);
|
||||
if (ImGui::BeginCombo("Thread", cur_thread ? cur_script_name : "(Select)"))
|
||||
{
|
||||
for (auto script : *Pointers.ScriptThreads)
|
||||
{
|
||||
if (script)
|
||||
{
|
||||
if (script->m_Context.m_State == rage::scrThread::State::KILLED || script->m_Context.m_StackSize == 0)
|
||||
continue;
|
||||
|
||||
ImGui::PushID(script->m_Context.m_ThreadId);
|
||||
|
||||
auto script_name = script->m_ScriptName;
|
||||
|
||||
if (ImGui::Selectable(script_name, cur_thread == script))
|
||||
{
|
||||
cur_thread = script;
|
||||
cur_script_name = script_name;
|
||||
cur_script_hash = script->m_Context.m_ScriptHash;
|
||||
}
|
||||
|
||||
if (cur_thread == script)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (cur_thread && (cur_thread->m_Context.m_ScriptHash != cur_script_hash || cur_thread->m_Context.m_StackSize == 0 || cur_thread->m_Context.m_State == rage::scrThread::State::KILLED))
|
||||
cur_thread = nullptr;
|
||||
|
||||
if (!cur_thread)
|
||||
return;
|
||||
}));
|
||||
|
||||
auto editor = std::make_unique<Group>("Editor");
|
||||
editor->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
if (!cur_thread)
|
||||
{
|
||||
ImGui::TextDisabled("Invalid");
|
||||
return;
|
||||
}
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputText("Script", scriptName, sizeof(scriptName));
|
||||
|
||||
DrawSavedVariable(cur_local);
|
||||
DrawSavedVariableEdit(cur_local, cur_local.Read(cur_thread));
|
||||
curThread = Scripts::FindScriptThread(Joaat(scriptName));
|
||||
if (!curThread)
|
||||
return ImGui::TextDisabled("Invalid");
|
||||
|
||||
DrawSavedVariable(curLocal);
|
||||
DrawSavedVariableEdit(curLocal, curLocal.Read(curThread));
|
||||
}));
|
||||
|
||||
auto saved = std::make_unique<Group>("Saved");
|
||||
saved->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
if (!cur_thread)
|
||||
if (!curThread)
|
||||
return ImGui::TextDisabled("Invalid");
|
||||
|
||||
auto scriptIdf = curThread->m_ScriptHash;
|
||||
if (scriptIdf != curLocal.script)
|
||||
{
|
||||
ImGui::TextDisabled("Invalid");
|
||||
return;
|
||||
curLocal = SavedLocal();
|
||||
curLocal.script = scriptIdf;
|
||||
}
|
||||
|
||||
auto script_idf = cur_thread->m_ScriptHash;
|
||||
|
||||
// refresh local if script changes (TODO not always the best idea)
|
||||
if (script_idf != cur_local.script)
|
||||
{
|
||||
cur_local = SavedLocal();
|
||||
cur_local.script = script_idf;
|
||||
}
|
||||
|
||||
if (ImGui::BeginListBox("##savedglobals", ImVec2(200, 200)))
|
||||
if (ImGui::BeginListBox("##savedlocals", ImVec2(200, 200)))
|
||||
{
|
||||
for (auto& var : SavedVariables::GetSavedLocals())
|
||||
{
|
||||
if (var.script != script_idf)
|
||||
if (var.script != scriptIdf)
|
||||
continue;
|
||||
|
||||
if (ImGui::Selectable(var.name.c_str(), var.name == cur_local.name))
|
||||
if (ImGui::Selectable(var.name.c_str(), var.name == curLocal.name))
|
||||
{
|
||||
cur_local = var;
|
||||
strncpy(local_name, var.name.c_str(), sizeof(local_name));
|
||||
curLocal = var;
|
||||
strncpy(localName, var.name.c_str(), sizeof(localName));
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::BeginListBox("##globalvalues", ImVec2(200, 200)))
|
||||
if (ImGui::BeginListBox("##localvalues", ImVec2(200, 200)))
|
||||
{
|
||||
for (auto& var : SavedVariables::GetSavedLocals())
|
||||
{
|
||||
if (var.script != script_idf)
|
||||
if (var.script != scriptIdf)
|
||||
continue;
|
||||
|
||||
DrawSavedVariablePreview(var, var.Read(cur_thread));
|
||||
DrawSavedVariablePreview(var, var.Read(curThread));
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
@@ -162,25 +100,24 @@ namespace YimMenu::Submenus
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::SetNextItemWidth(200.f);
|
||||
ImGui::InputText("##local_name", local_name, sizeof(local_name));
|
||||
ImGui::InputText("##localname", localName, sizeof(localName));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Save"))
|
||||
{
|
||||
cur_local.name = local_name;
|
||||
SaveLocal(cur_local);
|
||||
curLocal.name = localName;
|
||||
SaveLocal(curLocal);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Delete"))
|
||||
{
|
||||
cur_local.name = local_name;
|
||||
DeleteLocal(cur_local);
|
||||
cur_local = SavedLocal();
|
||||
curLocal.name = localName;
|
||||
DeleteLocal(curLocal);
|
||||
curLocal = SavedLocal();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
}));
|
||||
|
||||
locals->AddItem(std::move(script));
|
||||
locals->AddItem(std::move(editor));
|
||||
locals->AddItem(std::move(saved));
|
||||
return locals;
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "Scripts.hpp"
|
||||
#include "core/backend/FiberPool.hpp"
|
||||
#include "core/backend/ScriptMgr.hpp"
|
||||
#include "core/frontend/Notifications.hpp"
|
||||
#include "game/gta/data/ScriptNames.hpp"
|
||||
#include "game/gta/data/StackSizes.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "types/rage/atArray.hpp"
|
||||
#include "types/script/GtaThread.hpp"
|
||||
#include "types/script/CGameScriptHandlerNetComponent.hpp"
|
||||
#include "types/network/CNetGamePlayer.hpp"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
std::shared_ptr<Category> BuildScriptsMenu()
|
||||
{
|
||||
auto scripts = std::make_unique<Category>("Scripts");
|
||||
|
||||
auto threads = std::make_unique<Group>("Threads");
|
||||
auto script = std::make_unique<Group>("Start Script");
|
||||
|
||||
static rage::scrThread* curThread = nullptr;
|
||||
static std::string scriptSearch = "";
|
||||
static std::string scriptName = "";
|
||||
static std::string stackSizeName = stackSizes[0].first;
|
||||
static int stackSize = 0;
|
||||
|
||||
threads->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
if (!Pointers.ScriptThreads || Pointers.ScriptThreads->size() == 0)
|
||||
{
|
||||
curThread = nullptr;
|
||||
return ImGui::TextDisabled("None");
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Thread", curThread ? curThread->m_ScriptName : "(Select)"))
|
||||
{
|
||||
for (auto thread : *Pointers.ScriptThreads)
|
||||
{
|
||||
if (thread)
|
||||
{
|
||||
if (thread->m_Context.m_State == rage::scrThread::State::KILLED || thread->m_Context.m_StackSize == 0)
|
||||
continue;
|
||||
|
||||
ImGui::PushID(thread->m_Context.m_ThreadId);
|
||||
|
||||
if (ImGui::Selectable(thread->m_ScriptName, curThread == thread))
|
||||
{
|
||||
curThread = thread;
|
||||
}
|
||||
|
||||
if (curThread == thread)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (!curThread)
|
||||
return;
|
||||
|
||||
ImGui::Combo("State", (int*)&curThread->m_Context.m_State, "Idle\0Running\0Killed\0Paused\0Unk4\0");
|
||||
|
||||
if (auto netComponent = reinterpret_cast<GtaThread*>(curThread)->m_NetComponent)
|
||||
{
|
||||
if (auto host = netComponent->GetHost())
|
||||
{
|
||||
ImGui::Text("Host: %s", host->GetName());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(netComponent->IsLocalPlayerHost());
|
||||
if (ImGui::SmallButton("Take Control"))
|
||||
{
|
||||
FiberPool::Push([] {
|
||||
Scripts::ForceScriptHost(curThread);
|
||||
});
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
ImGui::Text("Thread ID: %d", curThread->m_Context.m_ThreadId);
|
||||
ImGui::Text("Stack Size: %d", curThread->m_Context.m_StackSize);
|
||||
ImGui::Text("Stack Pointer: 0x%X", &curThread->m_Context.m_StackPointer);
|
||||
ImGui::Text("Program Counter: 0x%X", &curThread->m_Context.m_ProgramCounter); // This is not really accurate (always points to the WAIT)
|
||||
if (curThread->m_Context.m_State == rage::scrThread::State::KILLED)
|
||||
ImGui::Text("Exit Reason: %s", curThread->m_ErrorMessage);
|
||||
}));
|
||||
|
||||
script->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
ImGui::InputTextWithHint("Script Name", "Search", &scriptSearch);
|
||||
|
||||
if (ImGui::BeginCombo("Stack Size", stackSizeName.c_str()))
|
||||
{
|
||||
for (auto& p : stackSizes)
|
||||
{
|
||||
if (ImGui::Selectable(std::format("{} ({})", p.first, (int)p.second).data(), stackSize == p.second))
|
||||
{
|
||||
stackSizeName = p.first;
|
||||
stackSize = p.second;
|
||||
}
|
||||
|
||||
if (p.second == stackSize)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginListBox("##scripts"))
|
||||
{
|
||||
std::string lowerSearch = scriptSearch;
|
||||
std::transform(lowerSearch.begin(), lowerSearch.end(), lowerSearch.begin(), ::tolower);
|
||||
for (auto& script : scriptNames)
|
||||
{
|
||||
std::string lowerScript = script;
|
||||
std::transform(lowerScript.begin(), lowerScript.end(), lowerScript.begin(), ::tolower);
|
||||
if (lowerScript.find(lowerSearch) != std::string::npos)
|
||||
{
|
||||
if (ImGui::Selectable(script, scriptName == script))
|
||||
{
|
||||
scriptSearch = script;
|
||||
scriptName = script;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Start Script"))
|
||||
{
|
||||
FiberPool::Push([] {
|
||||
auto hash = Joaat(scriptName);
|
||||
|
||||
if (!SCRIPT::DOES_SCRIPT_WITH_NAME_HASH_EXIST(hash))
|
||||
{
|
||||
Notifications::Show("Start Script", "Script does not exist.", NotificationType::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(hash) > 0)
|
||||
{
|
||||
Notifications::Show("Start Script", "Script is already running.", NotificationType::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MISC::GET_NUMBER_OF_FREE_STACKS_OF_THIS_SIZE(stackSize) == 0)
|
||||
{
|
||||
Notifications::Show("Start Script", "No free stack.", NotificationType::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!SCRIPT::HAS_SCRIPT_WITH_NAME_HASH_LOADED(hash))
|
||||
{
|
||||
SCRIPT::REQUEST_SCRIPT_WITH_NAME_HASH(hash);
|
||||
ScriptMgr::Yield();
|
||||
}
|
||||
|
||||
BUILTIN::START_NEW_SCRIPT_WITH_NAME_HASH(hash, stackSize);
|
||||
SCRIPT::SET_SCRIPT_WITH_NAME_HASH_AS_NO_LONGER_NEEDED(hash);
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
scripts->AddItem(std::move(threads));
|
||||
scripts->AddItem(std::move(script));
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "core/frontend/manager/Category.hpp"
|
||||
#include "game/frontend/items/Items.hpp"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
std::shared_ptr<Category> BuildScriptsMenu();
|
||||
}
|
||||
@@ -117,7 +117,6 @@ namespace YimMenu::Submenus
|
||||
{
|
||||
if (auto eventProgram = Scripts::FindScriptProgram(randomEventScripts[(int)selectedEvent]))
|
||||
{
|
||||
// TO-DO: Cache these too?
|
||||
if (NetComponent->IsLocalPlayerHost())
|
||||
{
|
||||
std::string ptrName = "SetFMContentScriptServerState" + std::to_string(selectedEvent);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
enum eStackSizes
|
||||
{
|
||||
MICRO = 128,
|
||||
MINI = 512,
|
||||
DEFAULT = 1424,
|
||||
SPECIAL_ABILITY = 1828,
|
||||
FRIEND = 2050,
|
||||
SHOP = 2324,
|
||||
CELLPHONE = 2552,
|
||||
VEHICLE_SPAWN = 3568,
|
||||
CAR_MOD_SHOP = 3750,
|
||||
PAUSE_MENU_SCRIPT = 3076,
|
||||
APP_INTERNET = 4592,
|
||||
MULTIPLAYER_MISSION = 5050,
|
||||
CONTACTS_APP = 4000,
|
||||
INTERACTION_MENU = 9800,
|
||||
SCRIPT_XML = 8344,
|
||||
PROPERTY_INT = 19400,
|
||||
ACTIVITY_CREATOR_INT = 15900,
|
||||
SMPL_INTERIOR = 2512,
|
||||
WAREHOUSE = 14100,
|
||||
IE_DELIVERY = 2324,
|
||||
SHOP_CONTROLLER = 3800,
|
||||
AM_MP_YACHT = 5000,
|
||||
INGAMEHUD = 4600,
|
||||
TRANSITION = 8032,
|
||||
FMMC_LAUNCHER = 27000,
|
||||
MULTIPLAYER_FREEMODE = 87500,
|
||||
MISSION = 63500,
|
||||
MP_LAUNCH_SCRIPT = 34750
|
||||
};
|
||||
|
||||
static constexpr std::pair<const char*, eStackSizes> stackSizes[] = {
|
||||
{"MICRO", MICRO},
|
||||
{"MINI", MINI},
|
||||
{"DEFAULT", DEFAULT},
|
||||
{"SPECIAL_ABILITY", SPECIAL_ABILITY},
|
||||
{"FRIEND", FRIEND},
|
||||
{"SHOP", SHOP},
|
||||
{"CELLPHONE", CELLPHONE},
|
||||
{"VEHICLE_SPAWN", VEHICLE_SPAWN},
|
||||
{"CAR_MOD_SHOP", CAR_MOD_SHOP},
|
||||
{"PAUSE_MENU_SCRIPT", PAUSE_MENU_SCRIPT},
|
||||
{"APP_INTERNET", APP_INTERNET},
|
||||
{"MULTIPLAYER_MISSION", MULTIPLAYER_MISSION},
|
||||
{"CONTACTS_APP", CONTACTS_APP},
|
||||
{"INTERACTION_MENU", INTERACTION_MENU},
|
||||
{"SCRIPT_XML", SCRIPT_XML},
|
||||
{"PROPERTY_INT", PROPERTY_INT},
|
||||
{"ACTIVITY_CREATOR_INT", ACTIVITY_CREATOR_INT},
|
||||
{"SMPL_INTERIOR", SMPL_INTERIOR},
|
||||
{"WAREHOUSE", WAREHOUSE},
|
||||
{"IE_DELIVERY", IE_DELIVERY},
|
||||
{"SHOP_CONTROLLER", SHOP_CONTROLLER},
|
||||
{"AM_MP_YACHT", AM_MP_YACHT},
|
||||
{"INGAMEHUD", INGAMEHUD},
|
||||
{"TRANSITION", TRANSITION},
|
||||
{"FMMC_LAUNCHER", FMMC_LAUNCHER},
|
||||
{"MULTIPLAYER_FREEMODE", MULTIPLAYER_FREEMODE},
|
||||
{"MISSION", MISSION},
|
||||
{"MP_LAUNCH_SCRIPT", MP_LAUNCH_SCRIPT}
|
||||
};
|
||||
}
|
||||
@@ -31,6 +31,7 @@ using Vector3 = rage::scrVector;
|
||||
#define INTERIOR_INDEX alignas(8) Interior
|
||||
#define NETWORK_INDEX alignas(8) int
|
||||
|
||||
#define SCR_SIZEOF(x) (sizeof(x) / 8)
|
||||
#define SCR_HASH alignas(8) Hash
|
||||
#define SCR_INT alignas(8) int
|
||||
#define SCR_BOOL alignas(8) BOOL
|
||||
|
||||
Reference in New Issue
Block a user