diff --git a/src/game/frontend/submenus/Recovery/StatEditor.cpp b/src/game/frontend/submenus/Recovery/StatEditor.cpp index 530ce54a9..ecb024537 100644 --- a/src/game/frontend/submenus/Recovery/StatEditor.cpp +++ b/src/game/frontend/submenus/Recovery/StatEditor.cpp @@ -1,8 +1,10 @@ -#include "StatEditor.hpp" -#include "core/backend/FiberPool.hpp" +#include "core/backend/FiberPool.hpp" +#include "core/frontend/widgets/imgui_bitfield.hpp" #include "game/backend/AnticheatBypass.hpp" -#include "game/pointers/Pointers.hpp" #include "game/gta/Natives.hpp" +#include "game/gta/Stats.hpp" +#include "game/pointers/Pointers.hpp" +#include "StatEditor.hpp" #include "types/stats/CStatsMgr.hpp" namespace YimMenu::Submenus @@ -10,11 +12,11 @@ namespace YimMenu::Submenus struct StatInfo { std::string m_Name; - std::uint32_t m_NameHash; + std::uint32_t m_NameHash = 0; bool m_Normalized = false; sStatData* m_Data = nullptr; - bool IsValid() + bool IsValid() const { return m_Data != nullptr; } @@ -26,7 +28,7 @@ namespace YimMenu::Submenus bool m_IsBoolStat; bool m_IsValid; - bool IsValid() + bool IsValid() const { return m_IsValid; } @@ -128,6 +130,7 @@ namespace YimMenu::Submenus value.m_AsU64 = data->GetInt64(); return; case sStatData::Type::UINT64: + case sStatData::Type::PACKED: value.m_AsU64 = data->GetUInt64(); return; case sStatData::Type::STRING: @@ -154,16 +157,30 @@ namespace YimMenu::Submenus case sStatData::Type::UINT8: STATS::STAT_SET_INT(hash, value.m_AsInt, true); return; - case sStatData::Type::INT64: - data->SetInt64(value.m_AsU64); // TODO this isn't a good idea! natives can't set this + case sStatData::Type::INT64: + data->SetInt64(value.m_AsU64 - 1); + STATS::STAT_INCREMENT(hash, static_cast(1)); return; case sStatData::Type::UINT64: - STATS::STAT_SET_MASKED_INT(hash, (std::uint32_t)value.m_AsU64, 0, 32, true); - STATS::STAT_SET_MASKED_INT(hash, (std::uint32_t)(value.m_AsU64 >> 32), 32, 32, true); + //Stats::SetMaskedAll(hash, value.m_AsU64); + //This code is simpler + //After writing, restarting will restore the data + data->SetUInt64(value.m_AsU64 - 1); + //You need to use STATS::STAT_INCREMENT to save the data on the server. + STATS::STAT_INCREMENT(hash, static_cast(1)); return; case sStatData::Type::STRING: STATS::STAT_SET_STRING(hash, value.m_AsString, true); return; + case sStatData::Type::PACKED: + /*data->SetUInt64(value.m_AsU64 - 1); + Packed data can't be written using STATS::STAT_INCREMENT + STATS::STAT_INCREMENT(hash, static_cast(1));*/ + Stats::SetMaskedAll(hash, value.m_AsU64); + return; + case sStatData::Type::POS: + case sStatData::Type::DATE: + case sStatData::Type::PROFILE_SETTING: default: return; // data type not supported } @@ -208,20 +225,24 @@ namespace YimMenu::Submenus case sStatData::Type::INT64: { auto int64_ = std::strtoll(value.data(), nullptr, 10); - data->SetInt64(int64_); // TODO this isn't a good idea! natives can't set this + data->SetInt64(int64_-1); + STATS::STAT_INCREMENT(hash, static_cast(1)); return; } case sStatData::Type::UINT64: { auto uint64_ = std::strtoull(value.data(), nullptr, 10); - - STATS::STAT_SET_MASKED_INT(hash, (std::uint32_t)uint64_, 0, 32, true); - STATS::STAT_SET_MASKED_INT(hash, (std::uint32_t)(uint64_ >> 32), 32, 32, true); + data->SetUInt64(uint64_ - 1); + STATS::STAT_INCREMENT(hash, static_cast(1)); return; } case sStatData::Type::STRING: STATS::STAT_SET_STRING(hash, value.data(), true); return; + case sStatData::Type::PACKED: + auto uint64_ = std::strtoull(value.data(), nullptr, 10); + Stats::SetMaskedAll(hash, uint64_); + return; default: return; // data type not supported } @@ -245,11 +266,13 @@ namespace YimMenu::Submenus case sStatData::Type::UINT8: return ImGui::InputScalar("Value", ImGuiDataType_U8, &value.m_AsInt); case sStatData::Type::INT64: - return ImGui::InputScalar("Value", ImGuiDataType_S64, &value.m_AsInt); + return ImGui::InputScalar("Value", ImGuiDataType_S64, &value.m_AsU64); case sStatData::Type::UINT64: - return ImGui::InputScalar("Value", ImGuiDataType_U64, &value.m_AsInt); + return ImGui::InputScalar("Value", ImGuiDataType_U64, &value.m_AsU64); case sStatData::Type::STRING: return ImGui::InputText("Value", value.m_AsString, sizeof(value.m_AsString)); + case sStatData::Type::PACKED: + return ImGui::Bitfield("Value", &value.m_AsU64); default: ImGui::BeginDisabled(); ImGui::Text("Data type not supported"); diff --git a/src/game/gta/Stats.cpp b/src/game/gta/Stats.cpp index 51d3bcc7f..8189faa3d 100644 --- a/src/game/gta/Stats.cpp +++ b/src/game/gta/Stats.cpp @@ -1,4 +1,4 @@ -#include "Stats.hpp" +#include "Stats.hpp" #include "game/gta/Natives.hpp" namespace YimMenu::Stats @@ -132,4 +132,60 @@ namespace YimMenu::Stats STATS::STAT_GET_MASKED_INT(Joaat(statName), &value, bitIndex, bitSize, -1); return value; } + + + void Stats::SetMaskedAll(Hash hash, uint64_t value) + { + uint64_t uint64_value = value; + int part0 = uint64_value & 0xFFFFu; + int part1 = (uint64_value >> 16) & 0xFFFFu; + int part2 = (uint64_value >> 32) & 0xFFFFu; + int part3 = (uint64_value >> 48) & 0xFFFFu; + // The second input parameter is of type int. Using -1 will cause the entire data to overflow + //so you have to split the 64-bit data into 4 parts to write it. + STATS::STAT_SET_MASKED_INT(hash, part0, 0, 16, true); //bit0-bit15 + STATS::STAT_SET_MASKED_INT(hash, part1, 16, 16, true); //bit16-bit31 + STATS::STAT_SET_MASKED_INT(hash, part2, 32, 16, true); //bit32-bit47 + STATS::STAT_SET_MASKED_INT(hash, part3, 48, 16, true); //bit48-bit63 + } + + void Stats::SetMaskedAll(std::string statName, uint64_t value) + { + ConvertMPX(statName); + uint64_t uint64_value = value; + int part0 = uint64_value & 0xFFFFu; + int part1 = (uint64_value >> 16) & 0xFFFFu; + int part2 = (uint64_value >> 32) & 0xFFFFu; + int part3 = (uint64_value >> 48) & 0xFFFFu; + + auto hash = Joaat(statName); + STATS::STAT_SET_MASKED_INT(hash, part0, 0, 16, true); //bit0-bit15 + STATS::STAT_SET_MASKED_INT(hash, part1, 16, 16, true); //bit16-bit31 + STATS::STAT_SET_MASKED_INT(hash, part2, 32, 16, true); //bit32-bit47 + STATS::STAT_SET_MASKED_INT(hash, part3, 48, 16, true); //bit48-bit63 + } + + uint64_t GetMaskedAll(Hash hash, int playerindex) + { + int part0 = 0, part1 = 0, part2 = 0, part3 = 0; + STATS::STAT_GET_MASKED_INT(hash, &part0, 0, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part1, 16, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part2, 32, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part3, 48, 16, playerindex); + uint64_t value = (static_cast(part3) << 48) | (static_cast(part2) << 32) | (static_cast(part1) << 16) | part0; + return value; + } + + uint64_t GetMaskedAll(std::string statName, int playerindex) + { + Hash hash = Joaat(statName); + int part0 = 0, part1 = 0, part2 = 0, part3 = 0; + STATS::STAT_GET_MASKED_INT(hash, &part0, 0, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part1, 16, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part2, 32, 16, playerindex); + STATS::STAT_GET_MASKED_INT(hash, &part3, 48, 16, playerindex); + uint64_t value = (static_cast(part3) << 48) | (static_cast(part2) << 32) | (static_cast(part1) << 16) | part0; + return value; + } + } \ No newline at end of file diff --git a/src/game/gta/Stats.hpp b/src/game/gta/Stats.hpp index 531f8990f..d68d52f1b 100644 --- a/src/game/gta/Stats.hpp +++ b/src/game/gta/Stats.hpp @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "core/util/Joaat.hpp" #include "types/script/types.hpp" @@ -7,7 +7,7 @@ namespace YimMenu::Stats extern int GetCharIndex(); extern void SetInt(std::string statName, int value); - extern void SetBool(std::string statName, bool value); + extern void SetBool(std::string statName, bool value = true); extern void SetFloat(std::string statName, float value); extern void SetDate(std::string statName, Date* value); extern void SetString(std::string statName, const char* value); @@ -26,4 +26,11 @@ namespace YimMenu::Stats extern void SetMaskedInt(std::string statName, int bitStart, int bitSize, int value); extern bool GetMaskedBool(std::string statName, int bitIndex); extern int GetMaskedInt(std::string statName, int bitIndex, int bitSize); + + //You can directly write/read all packed int/bool and uint64 statistics. + //pos/date seems to work too,but the data structure is still unclear for now. + extern void SetMaskedAll(std::string statName, uint64_t value); + extern void SetMaskedAll(Hash hash, uint64_t value); + uint64_t GetMaskedAll(Hash hash, int playerindex=-1); + uint64_t GetMaskedAll(std::string statName, int playerindex = -1); } \ No newline at end of file diff --git a/src/types/stats/sStatData.hpp b/src/types/stats/sStatData.hpp index 7e4a61706..79da02a01 100644 --- a/src/types/stats/sStatData.hpp +++ b/src/types/stats/sStatData.hpp @@ -1,10 +1,11 @@ -#pragma once +#pragma once class sStatData { public: enum class Type { + NONE=0, INT = 1, FLOAT, STRING, @@ -15,7 +16,11 @@ class sStatData UINT64, DATE = 20, POS, - INT64 = 26, + TEXTLABEL = 22, + PACKED = 23, + USERID = 24, + PROFILE_SETTING = 25, + INT64 = 26 }; // it isn't recommended to call the SetXXX() functions directly, use the natives instead