Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/gta/stat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class sStatData
virtual void _29() = 0;
virtual bool IsZero() = 0;

uint8_t GetCharIndex()
{
uint8_t index = m_flags >> 0x14 & 7;
return index == 6 || index == 7 ? 0 : index;
}

uint64_t m_flags;
};

Expand Down
102 changes: 50 additions & 52 deletions src/services/stats/stats_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "gta/stat.hpp"
#include "pointers.hpp"

#include <chrono>
#include <cstddef>

namespace big
Expand Down Expand Up @@ -141,33 +142,22 @@ namespace big
pso_file.read(buf, size);
}

inline uint8_t get_char_index_from_stat(sStatData* stat)
{
if (stat == nullptr)
{
LOG(FATAL) << "stat is nullptr wtf?";
return 0;
}
uint8_t index = stat->m_flags >> 0x14 & 7;
return index == 6 || index == 7 ? 0 : index;
}

template<typename T>
void stats_service::save_stat_map_to_json(nlohmann::json& json, T& map, bool use_stat_names, uint8_t char_index)
{
auto stats = nlohmann::json::object();
for (auto stat : map)
for (const auto& stat : map)
{
if (get_char_index_from_stat(get_stat_by_hash(stat.first)) != char_index)
if (stat.second.m_character_index != char_index)
continue;

if (use_stat_names)
{
stats[m_stat_hash_to_string[stat.first]] = stat.second;
stats[m_stat_hash_to_string[stat.first]] = stat.second.data;
}
else
{
stats[std::to_string(stat.first)] = stat.second;
stats[std::to_string(stat.first)] = stat.second.data;
}
}
json = stats;
Expand All @@ -192,9 +182,10 @@ namespace big
{
Hash stat_hash = use_stat_names ? rage::joaat(stat.key()) : std::stoul(stat.key());

if (get_stat_by_hash(stat_hash))
sStatData* stat_ptr = get_stat_by_hash(stat_hash);
if (stat_ptr != nullptr)
{
map[stat_hash] = stat.value();
map[stat_hash] = {stat.value(), stat_ptr->GetCharIndex()};
}
else
{
Expand All @@ -209,9 +200,10 @@ namespace big
{
Hash stat_hash = use_stat_names ? rage::joaat(stat[0]) : stat[0].get<Hash>();

if (get_stat_by_hash(stat_hash))
sStatData* stat_ptr = get_stat_by_hash(stat_hash);
if (stat_ptr != nullptr)
{
map[stat_hash] = stat[1];
map[stat_hash] = {stat[1], stat_ptr->GetCharIndex()};
}
else
{
Expand Down Expand Up @@ -402,7 +394,6 @@ namespace big

try
{
// Ignore comments for save_overwrite.json
const nlohmann::json& json = nlohmann::json::parse(file, nullptr, true, /*ignore_comments*/ true);
bool uses_human_readable_stat_names = json["uses_human_readable_stat_names"];
load_stat_map_from_json(json["INT"], m_int_stats, uses_human_readable_stat_names);
Expand Down Expand Up @@ -430,7 +421,7 @@ namespace big
return false;
}

bool stats_service::load_internal_script_data_from_json()
bool stats_service::load_script_data()
{
if (!m_save_file_script.exists())
{
Expand All @@ -457,6 +448,8 @@ namespace big

void stats_service::save_stats()
{
std::chrono::time_point start_time = std::chrono::high_resolution_clock::now();

const auto& stats = *g_pointers->m_stats;
for (const auto& stat : stats)
{
Expand All @@ -471,72 +464,72 @@ namespace big
{
case eStatType::INT:
{
m_int_stats[stat.m_hash] = stat.m_stat->GetIntData();
m_int_stats[stat.m_hash] = {stat.m_stat->GetIntData(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::FLOAT:
{
m_float_stats[stat.m_hash] = stat.m_stat->GetFloatData();
m_float_stats[stat.m_hash] = {stat.m_stat->GetFloatData(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::STRING:
{
m_string_stats[stat.m_hash] = std::string(stat.m_stat->GetStringData());
m_string_stats[stat.m_hash] = {std::string(stat.m_stat->GetStringData()), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::BOOL_:
{
m_bool_stats[stat.m_hash] = stat.m_stat->GetBoolData();
m_bool_stats[stat.m_hash] = {stat.m_stat->GetBoolData(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::UINT8:
{
m_uint8_stats[stat.m_hash] = stat.m_stat->GetUint8Data();
m_uint8_stats[stat.m_hash] = {stat.m_stat->GetUint8Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::UINT16:
{
m_uint16_stats[stat.m_hash] = stat.m_stat->GetUint16Data();
m_uint16_stats[stat.m_hash] = {stat.m_stat->GetUint16Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::UINT32:
{
m_uint32_stats[stat.m_hash] = stat.m_stat->GetUint32Data();
m_uint32_stats[stat.m_hash] = {stat.m_stat->GetUint32Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::UINT64:
{
m_uint64_stats[stat.m_hash] = stat.m_stat->GetUint64Data();
m_uint64_stats[stat.m_hash] = {stat.m_stat->GetUint64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::INT64:
{
m_int64_stats[stat.m_hash] = stat.m_stat->GetInt64Data();
m_int64_stats[stat.m_hash] = {stat.m_stat->GetInt64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::DATE:
{
m_date_stats[stat.m_hash] = stat.m_stat->GetUint64Data();
m_date_stats[stat.m_hash] = {stat.m_stat->GetUint64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::POS:
{
m_pos_stats[stat.m_hash] = stat.m_stat->GetUint64Data();
m_pos_stats[stat.m_hash] = {stat.m_stat->GetUint64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::TEXTLABEL:
{
m_textlabel_stats[stat.m_hash] = stat.m_stat->GetIntData();
m_textlabel_stats[stat.m_hash] = {stat.m_stat->GetIntData(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::PACKED:
{
m_packed_stats[stat.m_hash] = stat.m_stat->GetUint64Data();
m_packed_stats[stat.m_hash] = {stat.m_stat->GetUint64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::USERID:
{
m_userid_stats[stat.m_hash] = stat.m_stat->GetUint64Data();
m_userid_stats[stat.m_hash] = {stat.m_stat->GetUint64Data(), stat.m_stat->GetCharIndex()};
break;
}
case eStatType::PROFILE_SETTING: break;
Expand All @@ -553,23 +546,25 @@ namespace big
save_internal_stats_to_json(2);

save_script_data_to_json();

std::chrono::time_point end_time = std::chrono::high_resolution_clock::now();
LOGIF(VERBOSE, g.enable_debug_logs, "Saving took {:%S}", std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time));
}

bool stats_service::load_stats()
{
std::chrono::time_point start_time = std::chrono::high_resolution_clock::now();
if (!load_internal_stats_from_json(0))
{
return false;
}

// Load character stats if they exist.
load_internal_stats_from_json(1);
load_internal_stats_from_json(2);

// Load stat overrides last.
load_internal_stats_from_json(SAVE_OVERWRITE_INDEX);

load_internal_script_data_from_json();
load_script_data();

const auto& stats = *g_pointers->m_stats;
for (const auto& stat : stats)
Expand All @@ -579,85 +574,85 @@ namespace big
case eStatType::INT:
{
if (m_int_stats.contains(stat.m_hash))
stat.m_stat->SetIntData(m_int_stats[stat.m_hash]);
stat.m_stat->SetIntData(m_int_stats[stat.m_hash].data);
break;
}
case eStatType::FLOAT:
{
if (m_float_stats.contains(stat.m_hash))
stat.m_stat->SetFloatData(m_float_stats[stat.m_hash]);
stat.m_stat->SetFloatData(m_float_stats[stat.m_hash].data);
break;
}
case eStatType::STRING:
{
if (m_string_stats.contains(stat.m_hash))
strncpy(((sSubStatData<char[32]>*)stat.m_stat)->m_data, m_string_stats[stat.m_hash].data(), 32);
strncpy(((sSubStatData<char[32]>*)stat.m_stat)->m_data, m_string_stats[stat.m_hash].data.data(), 32);
break;
}
case eStatType::BOOL_:
{
if (m_bool_stats.contains(stat.m_hash))
stat.m_stat->SetBoolData(m_bool_stats[stat.m_hash]);
stat.m_stat->SetBoolData(m_bool_stats[stat.m_hash].data);
break;
}
case eStatType::UINT8:
{
if (m_uint8_stats.contains(stat.m_hash))
stat.m_stat->SetUint8Data(m_uint8_stats[stat.m_hash]);
stat.m_stat->SetUint8Data(m_uint8_stats[stat.m_hash].data);
break;
}
case eStatType::UINT16:
{
if (m_uint16_stats.contains(stat.m_hash))
stat.m_stat->SetUint16Data(m_uint16_stats[stat.m_hash]);
stat.m_stat->SetUint16Data(m_uint16_stats[stat.m_hash].data);
break;
}
case eStatType::UINT32:
{
if (m_uint32_stats.contains(stat.m_hash))
stat.m_stat->SetUint32Data(m_uint32_stats[stat.m_hash]);
stat.m_stat->SetUint32Data(m_uint32_stats[stat.m_hash].data);
break;
}
case eStatType::UINT64:
{
if (m_uint64_stats.contains(stat.m_hash))
stat.m_stat->SetUint64Data(m_uint64_stats[stat.m_hash]);
stat.m_stat->SetUint64Data(m_uint64_stats[stat.m_hash].data);
break;
}
case eStatType::INT64:
{
if (m_int64_stats.contains(stat.m_hash))
stat.m_stat->SetInt64Data(m_int64_stats[stat.m_hash]);
stat.m_stat->SetInt64Data(m_int64_stats[stat.m_hash].data);
break;
}
case eStatType::DATE:
{
if (m_date_stats.contains(stat.m_hash))
stat.m_stat->SetUint64Data(m_date_stats[stat.m_hash]);
stat.m_stat->SetUint64Data(m_date_stats[stat.m_hash].data);
break;
}
case eStatType::POS:
{
if (m_pos_stats.contains(stat.m_hash))
stat.m_stat->SetUint64Data(m_pos_stats[stat.m_hash]);
stat.m_stat->SetUint64Data(m_pos_stats[stat.m_hash].data);
break;
}
case eStatType::TEXTLABEL:
{
if (m_textlabel_stats.contains(stat.m_hash))
stat.m_stat->SetIntData(m_textlabel_stats[stat.m_hash]);
stat.m_stat->SetIntData(m_textlabel_stats[stat.m_hash].data);
break;
}
case eStatType::PACKED:
{
if (m_packed_stats.contains(stat.m_hash))
stat.m_stat->SetUint64Data(m_packed_stats[stat.m_hash]);
stat.m_stat->SetUint64Data(m_packed_stats[stat.m_hash].data);
break;
}
case eStatType::USERID:
{
if (m_userid_stats.contains(stat.m_hash))
stat.m_stat->SetUint64Data(m_userid_stats[stat.m_hash]);
stat.m_stat->SetUint64Data(m_userid_stats[stat.m_hash].data);
break;
}
case eStatType::PROFILE_SETTING: break;
Expand All @@ -674,6 +669,9 @@ namespace big
stat.m_stat->SetIntData(1);
}
}

std::chrono::time_point end_time = std::chrono::high_resolution_clock::now();
LOGIF(VERBOSE, g.enable_debug_logs, "Loading took {:%S}", std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time));
return true;
}
}
37 changes: 18 additions & 19 deletions src/services/stats/stats_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,12 @@ namespace big
void do_visit(const Ptr& ptr, const Fnc& fnc);
};

class sCustomStat
template <typename T>
class sSmallStat
{
public:
sStatData* m_stat;
bool m_is_character;
T data;
uint8_t m_character_index;
bool m_is_online;
};

class stats_service
Expand Down Expand Up @@ -151,7 +150,7 @@ namespace big
void save_internal_stats_to_json(uint8_t char_index = 0);
bool load_internal_stats_from_json(uint8_t char_index = 0);

bool load_internal_script_data_from_json();
bool load_script_data();

template<typename T>
void save_stat_map_to_json(nlohmann::json& json, T& map, bool use_stat_names, uint8_t char_index);
Expand All @@ -166,20 +165,20 @@ namespace big
void load_script_data_from_json(const nlohmann::json& json);
void save_script_data_to_json();

std::unordered_map<Hash, int> m_int_stats;
std::unordered_map<Hash, float> m_float_stats;
std::unordered_map<Hash, std::string> m_string_stats;
std::unordered_map<Hash, bool> m_bool_stats;
std::unordered_map<Hash, uint8_t> m_uint8_stats;
std::unordered_map<Hash, uint16_t> m_uint16_stats;
std::unordered_map<Hash, uint32_t> m_uint32_stats;
std::unordered_map<Hash, uint64_t> m_uint64_stats;
std::unordered_map<Hash, int64_t> m_int64_stats;
std::unordered_map<Hash, uint64_t> m_date_stats;
std::unordered_map<Hash, uint64_t> m_pos_stats;
std::unordered_map<Hash, int> m_textlabel_stats;
std::unordered_map<Hash, int64_t> m_packed_stats;
std::unordered_map<Hash, int64_t> m_userid_stats;
std::unordered_map<Hash, sSmallStat<int>> m_int_stats;
std::unordered_map<Hash, sSmallStat<float>> m_float_stats;
std::unordered_map<Hash, sSmallStat<std::string>> m_string_stats;
std::unordered_map<Hash, sSmallStat<bool>> m_bool_stats;
std::unordered_map<Hash, sSmallStat<uint8_t>> m_uint8_stats;
std::unordered_map<Hash, sSmallStat<uint16_t>> m_uint16_stats;
std::unordered_map<Hash, sSmallStat<uint32_t>> m_uint32_stats;
std::unordered_map<Hash, sSmallStat<uint64_t>> m_uint64_stats;
std::unordered_map<Hash, sSmallStat<int64_t>> m_int64_stats;
std::unordered_map<Hash, sSmallStat<uint64_t>> m_date_stats;
std::unordered_map<Hash, sSmallStat<uint64_t>> m_pos_stats;
std::unordered_map<Hash, sSmallStat<int>> m_textlabel_stats;
std::unordered_map<Hash, sSmallStat<uint64_t>> m_packed_stats;
std::unordered_map<Hash, sSmallStat<uint64_t>> m_userid_stats;

std::unordered_map<Hash, std::string> m_stat_hash_to_string;

Expand Down