Add player history

This commit is contained in:
RipleyTom 2024-02-01 07:38:22 +01:00 committed by Megamouse
parent c04cd2228e
commit c589001dff
5 changed files with 323 additions and 10 deletions

View file

@ -42,6 +42,7 @@
#endif
#include "util/asm.hpp"
#include "util/yaml.hpp"
#include <span>
@ -55,6 +56,63 @@ LOG_CHANNEL(ticket_log, "Ticket");
namespace np
{
std::string get_players_history_path()
{
#ifdef _WIN32
return fs::get_config_dir() + "config/players_history.yml";
#else
return fs::get_config_dir() + "players_history.yml";
#endif
}
std::map<std::string, player_history> load_players_history()
{
const auto parsing_error = [](std::string_view error) -> std::map<std::string, player_history>
{
nph_log.error("Error parsing %s: %s", get_players_history_path(), error);
return {};
};
std::map<std::string, player_history> history;
if (fs::file history_file{get_players_history_path(), fs::read + fs::create})
{
auto [yml_players_history, error] = yaml_load(history_file.to_string());
if (!error.empty())
return parsing_error(error);
for (const auto& player : yml_players_history)
{
std::string username = player.first.Scalar();
const auto& seq = player.second;
if (!seq.IsSequence() || seq.size() != 3)
return parsing_error("Player history is not a proper sequence!");
const u64 timestamp = get_yaml_node_value<u64>(seq[0], error);
if (!error.empty())
return parsing_error(error);
std::string description = seq[1].Scalar();
if (!seq[2].IsSequence())
return parsing_error("Expected communication ids sequence");
std::set<std::string> com_ids;
for (usz i = 0; i < seq[2].size(); i++)
{
com_ids.insert(seq[2][i].Scalar());
}
history.insert(std::make_pair(std::move(username), player_history{.timestamp = timestamp, .communication_ids = std::move(com_ids), .description = std::move(description)}));
}
}
return history;
}
ticket::ticket(std::vector<u8>&& raw_data)
: raw_data(raw_data)
{
@ -363,6 +421,13 @@ namespace np
np_handler::np_handler()
{
{
auto history = load_players_history();
std::lock_guard lock(mutex_history);
players_history = std::move(history);
}
g_fxo->need<named_thread<signaling_handler>>();
is_connected = (g_cfg.net.net_active == np_internet_status::enabled);
@ -1217,13 +1282,169 @@ namespace np
return ::at32(match2_req_results, event_key);
}
u32 np_handler::add_players_to_history(vm::cptr<SceNpId> /*npids*/, u32 /*count*/)
player_history& np_handler::get_player_and_set_timestamp(const SceNpId& npid, u64 timestamp)
{
std::string npid_str = std::string(npid.handle.data);
if (!players_history.contains(npid_str))
{
auto [it, success] = players_history.insert(std::make_pair(std::move(npid_str), player_history{.timestamp = timestamp}));
ensure(success);
return it->second;
}
auto& history = ::at32(players_history, npid_str);
history.timestamp = timestamp;
return history;
}
constexpr usz MAX_HISTORY_ENTRIES = 200;
void np_handler::add_player_to_history(const SceNpId* npid, const char* description)
{
std::lock_guard lock(mutex_history);
auto& history = get_player_and_set_timestamp(*npid, get_system_time());
if (description)
history.description = description;
while (players_history.size() > MAX_HISTORY_ENTRIES)
{
auto it = std::min_element(players_history.begin(), players_history.end(), [](const auto& a, const auto& b) { return a.second.timestamp < b.second.timestamp; } );
players_history.erase(it);
}
save_players_history();
}
u32 np_handler::add_players_to_history(const SceNpId* npids, const char* description, u32 count)
{
std::lock_guard lock(mutex_history);
const std::string communication_id_str = std::string(basic_handler.context.data);
for (u32 i = 0; i < count; i++)
{
auto& history = get_player_and_set_timestamp(npids[i], get_system_time());
if (description)
history.description = description;
history.communication_ids.insert(communication_id_str);
}
while (players_history.size() > MAX_HISTORY_ENTRIES)
{
auto it = std::min_element(players_history.begin(), players_history.end(), [](const auto& a, const auto& b) { return a.second.timestamp < b.second.timestamp; } );
players_history.erase(it);
}
save_players_history();
const u32 req_id = get_req_id(REQUEST_ID_HIGH::MISC);
send_basic_event(SCE_NP_BASIC_EVENT_ADD_PLAYERS_HISTORY_RESULT, 0, req_id);
return req_id;
}
u32 np_handler::get_players_history_count(u32 options)
{
const bool all_history = (options == SCE_NP_BASIC_PLAYERS_HISTORY_OPTIONS_ALL);
std::lock_guard lock(mutex_history);
if (all_history)
{
return ::size32(players_history);
}
const std::string communication_id_str = std::string(basic_handler.context.data);
u32 count = 0;
for (auto it = players_history.begin(); it != players_history.end(); it++)
{
if (it->second.communication_ids.contains(communication_id_str))
{
count++;
}
}
return count;
}
bool np_handler::get_player_history_entry(u32 options, u32 index, SceNpId* npid)
{
const bool all_history = (options == SCE_NP_BASIC_PLAYERS_HISTORY_OPTIONS_ALL);
std::lock_guard lock(mutex_history);
if (all_history)
{
auto it = players_history.begin();
std::advance(it, index);
if (it != players_history.end())
{
string_to_npid(it->first, *npid);
return true;
}
}
else
{
const std::string communication_id_str = std::string(basic_handler.context.data);
for (auto it = players_history.begin(); it != players_history.end(); it++)
{
if (it->second.communication_ids.contains(communication_id_str))
{
if (index == 0)
{
string_to_npid(it->first, *npid);
return true;
}
index--;
}
}
}
return false;
}
void np_handler::save_players_history()
{
#ifdef _WIN32
const std::string path_to_cfg = fs::get_config_dir() + "config/";
if (!fs::create_path(path_to_cfg))
{
nph_log.error("Could not create path: %s", path_to_cfg);
}
#endif
fs::file history_file(get_players_history_path(), fs::rewrite);
if (!history_file)
return;
YAML::Emitter out;
out << YAML::BeginMap;
for (const auto& [player_npid, player_info] : players_history)
{
out << player_npid;
out << YAML::BeginSeq;
out << player_info.timestamp;
out << player_info.description;
out << YAML::BeginSeq;
for (const auto& com_id : player_info.communication_ids)
{
out << com_id;
}
out << YAML::EndSeq;
out << YAML::EndSeq;
}
out << YAML::EndMap;
history_file.write(out.c_str(), out.size());
}
u32 np_handler::get_num_friends()
{
return get_rpcn()->get_num_friends();