cache loaded player files between sessions

This commit is contained in:
Martin Michelsen
2023-12-04 12:38:26 -08:00
parent e05dcb6e70
commit 01b83044dc
8 changed files with 148 additions and 11 deletions
+1
View File
@@ -153,6 +153,7 @@ Client::Client(
lobby_client_id(0),
lobby_arrow_color(0),
preferred_lobby_id(-1),
game_data(server->get_state()->player_files_manager),
save_game_data_event(
event_new(
bufferevent_get_base(bev), -1, EV_TIMEOUT | EV_PERSIST,
+1 -2
View File
@@ -31,7 +31,6 @@ private:
uint32_t local_connect_address;
uint32_t external_connect_address;
static void dispatch_on_receive_message(evutil_socket_t fd, short events,
void* ctx);
static void dispatch_on_receive_message(evutil_socket_t fd, short events, void* ctx);
void on_receive_message(int fd, short event);
};
+1 -1
View File
@@ -1698,7 +1698,7 @@ Action a_run_server_replay_log(
}
shared_ptr<struct event_base> base(event_base_new(), event_base_free);
auto state = make_shared<ServerState>(config_filename, is_replay);
auto state = make_shared<ServerState>(base, config_filename, is_replay);
state->init();
shared_ptr<DNSServer> dns_server;
+108 -4
View File
@@ -19,10 +19,90 @@
using namespace std;
ClientGameData::ClientGameData()
PlayerFilesManager::PlayerFilesManager(std::shared_ptr<struct event_base> base)
: base(base),
clear_expired_files_event(
event_new(this->base.get(), -1, EV_TIMEOUT | EV_PERSIST, &PlayerFilesManager::clear_expired_files, this),
event_free) {
auto tv = usecs_to_timeval(30 * 1000 * 1000);
event_add(this->clear_expired_files_event.get(), &tv);
}
template <typename KeyT, typename ValueT>
size_t erase_unused(std::unordered_map<KeyT, std::shared_ptr<ValueT>>& m) {
size_t ret = 0;
for (auto it = m.begin(); it != m.end();) {
if (it->second.use_count() <= 1) {
it = m.erase(it);
ret++;
} else {
it++;
}
}
return ret;
}
std::shared_ptr<PSOBBBaseSystemFile> PlayerFilesManager::get_system(const std::string& filename) {
try {
return this->loaded_system_files.at(filename);
} catch (const out_of_range&) {
return nullptr;
}
}
std::shared_ptr<PSOBBCharacterFile> PlayerFilesManager::get_character(const std::string& filename) {
try {
return this->loaded_character_files.at(filename);
} catch (const out_of_range&) {
return nullptr;
}
}
std::shared_ptr<PSOBBGuildCardFile> PlayerFilesManager::get_guild_card(const std::string& filename) {
try {
return this->loaded_guild_card_files.at(filename);
} catch (const out_of_range&) {
return nullptr;
}
}
void PlayerFilesManager::set_system(const std::string& filename, std::shared_ptr<PSOBBBaseSystemFile> file) {
if (!this->loaded_system_files.emplace(filename, file).second) {
throw runtime_error("Guild Card file already loaded");
}
}
void PlayerFilesManager::set_character(const std::string& filename, std::shared_ptr<PSOBBCharacterFile> file) {
if (!this->loaded_character_files.emplace(filename, file).second) {
throw runtime_error("character file already loaded");
}
}
void PlayerFilesManager::set_guild_card(const std::string& filename, std::shared_ptr<PSOBBGuildCardFile> file) {
if (!this->loaded_guild_card_files.emplace(filename, file).second) {
throw runtime_error("Guild Card file already loaded");
}
}
void PlayerFilesManager::clear_expired_files(evutil_socket_t, short, void* ctx) {
auto* self = reinterpret_cast<PlayerFilesManager*>(ctx);
size_t num_deleted = erase_unused(self->loaded_system_files);
if (num_deleted) {
player_data_log.info("Cleared %zu expired system file(s)", num_deleted);
}
num_deleted = erase_unused(self->loaded_character_files);
if (num_deleted) {
player_data_log.info("Cleared %zu expired character file(s)", num_deleted);
}
num_deleted = erase_unused(self->loaded_guild_card_files);
if (num_deleted) {
player_data_log.info("Cleared %zu expired Guild Card file(s)", num_deleted);
}
}
ClientGameData::ClientGameData(std::shared_ptr<PlayerFilesManager> files_manager)
: guild_card_number(0),
should_update_play_time(false),
bb_character_index(-1),
files_manager(files_manager),
last_play_time_update(0) {
for (size_t z = 0; z < this->blocked_senders.size(); z++) {
this->blocked_senders[z] = 0;
@@ -247,14 +327,23 @@ void ClientGameData::load_all_files() {
this->guild_card_data.reset();
string sys_filename = this->system_filename();
if (isfile(sys_filename)) {
this->system_data = this->files_manager->get_system(sys_filename);
if (this->system_data) {
player_data_log.info("Using loaded system file %s", sys_filename.c_str());
} else if (isfile(sys_filename)) {
this->system_data = make_shared<PSOBBBaseSystemFile>(load_object_file<PSOBBBaseSystemFile>(sys_filename, true));
this->files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Loaded system data from %s", sys_filename.c_str());
} else {
player_data_log.info("System file is missing: %s", sys_filename.c_str());
}
if (this->bb_character_index >= 0) {
string char_filename = this->character_filename();
if (isfile(char_filename)) {
this->character_data = this->files_manager->get_character(char_filename);
if (this->character_data) {
player_data_log.info("Using loaded character file %s", char_filename.c_str());
} else if (isfile(char_filename)) {
auto f = fopen_unique(char_filename, "rb");
auto header = freadx<PSOCommandHeaderBB>(f.get());
if (header.size != 0x399C) {
@@ -267,21 +356,31 @@ void ClientGameData::load_all_files() {
throw runtime_error("incorrect flag in character file header");
}
this->character_data = make_shared<PSOBBCharacterFile>(freadx<PSOBBCharacterFile>(f.get()));
this->files_manager->set_character(this->character_filename(), this->character_data);
player_data_log.info("Loaded character data from %s", char_filename.c_str());
// If there was no .psosys file, load the system file from the .psochar
// file instead
if (!this->system_data) {
this->system_data = make_shared<PSOBBBaseSystemFile>(freadx<PSOBBBaseSystemFile>(f.get()));
this->files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Loaded system data from %s", char_filename.c_str());
}
} else {
player_data_log.info("Character file is missing: %s", char_filename.c_str());
}
}
string card_filename = this->guild_card_filename();
if (isfile(card_filename)) {
this->guild_card_data = this->files_manager->get_guild_card(card_filename);
if (this->guild_card_data) {
player_data_log.info("Using loaded Guild Card file %s", card_filename.c_str());
} else if (isfile(card_filename)) {
this->guild_card_data = make_shared<PSOBBGuildCardFile>(load_object_file<PSOBBGuildCardFile>(card_filename));
this->files_manager->set_guild_card(card_filename, this->guild_card_data);
player_data_log.info("Loaded Guild Card data from %s", card_filename.c_str());
} else {
player_data_log.info("Guild Card file is missing: %s", card_filename.c_str());
}
// If any of the above files were missing, try to load from .nsa/.nsc files instead
@@ -295,20 +394,24 @@ void ClientGameData::load_all_files() {
}
if (!this->system_data) {
this->system_data = make_shared<PSOBBBaseSystemFile>(nsa_data->system_file.base);
this->files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Loaded legacy system data from %s", nsa_filename.c_str());
}
if (!this->guild_card_data) {
this->guild_card_data = make_shared<PSOBBGuildCardFile>(nsa_data->guild_card_file);
this->files_manager->set_guild_card(card_filename, this->guild_card_data);
player_data_log.info("Loaded legacy Guild Card data from %s", nsa_filename.c_str());
}
}
if (!this->system_data) {
this->system_data = make_shared<PSOBBBaseSystemFile>();
this->files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Created new system data");
}
if (!this->guild_card_data) {
this->guild_card_data = make_shared<PSOBBGuildCardFile>();
this->files_manager->set_guild_card(card_filename, this->guild_card_data);
player_data_log.info("Created new Guild Card data");
}
@@ -326,6 +429,7 @@ void ClientGameData::load_all_files() {
}
this->character_data = make_shared<PSOBBCharacterFile>();
this->files_manager->set_character(this->character_filename(), this->character_data);
this->character_data->inventory = nsc_data.inventory;
this->character_data->disp = nsc_data.disp;
this->character_data->play_time_seconds = nsc_data.disp.play_time;
+28 -1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <event2/event.h>
#include <inttypes.h>
#include <stddef.h>
@@ -30,6 +31,30 @@ struct PendingCardTrade {
std::vector<std::pair<uint32_t, uint32_t>> card_to_count;
};
class PlayerFilesManager {
public:
explicit PlayerFilesManager(std::shared_ptr<struct event_base> base);
~PlayerFilesManager() = default;
std::shared_ptr<PSOBBBaseSystemFile> get_system(const std::string& filename);
std::shared_ptr<PSOBBCharacterFile> get_character(const std::string& filename);
std::shared_ptr<PSOBBGuildCardFile> get_guild_card(const std::string& filename);
void set_system(const std::string& filename, std::shared_ptr<PSOBBBaseSystemFile> file);
void set_character(const std::string& filename, std::shared_ptr<PSOBBCharacterFile> file);
void set_guild_card(const std::string& filename, std::shared_ptr<PSOBBGuildCardFile> file);
private:
std::shared_ptr<struct event_base> base;
std::unique_ptr<struct event, void (*)(struct event*)> clear_expired_files_event;
std::unordered_map<std::string, std::shared_ptr<PSOBBBaseSystemFile>> loaded_system_files;
std::unordered_map<std::string, std::shared_ptr<PSOBBCharacterFile>> loaded_character_files;
std::unordered_map<std::string, std::shared_ptr<PSOBBGuildCardFile>> loaded_guild_card_files;
static void clear_expired_files(evutil_socket_t fd, short events, void* ctx);
};
class ClientGameData {
public:
uint32_t guild_card_number;
@@ -55,7 +80,7 @@ public:
ItemData identify_result;
std::array<std::vector<ItemData>, 3> shop_contents;
ClientGameData();
explicit ClientGameData(std::shared_ptr<PlayerFilesManager> files_manager);
~ClientGameData();
void create_battle_overlay(std::shared_ptr<const BattleRules> rules, std::shared_ptr<const LevelTable> level_table);
@@ -88,6 +113,8 @@ public:
void save_guild_card_file() const;
private:
std::shared_ptr<PlayerFilesManager> files_manager;
// The overlay character data is used in battle and challenge modes, when
// character data is temporarily replaced in-game. In other play modes and in
// lobbies, overlay_character_data is null.
+3 -1
View File
@@ -3113,7 +3113,9 @@ static void on_E3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
return;
}
ClientGameData temp_gd;
auto s = c->require_server_state();
ClientGameData temp_gd(s->player_files_manager);
temp_gd.guild_card_number = c->license->serial_number;
temp_gd.bb_username = c->license->bb_username;
temp_gd.bb_character_index = cmd.character_index;
+2 -1
View File
@@ -17,7 +17,7 @@
using namespace std;
ServerState::ServerState(const string& config_filename, bool is_replay)
ServerState::ServerState(shared_ptr<struct event_base> base, const string& config_filename, bool is_replay)
: config_filename(config_filename),
is_replay(is_replay),
dns_server_port(0),
@@ -42,6 +42,7 @@ ServerState::ServerState(const string& config_filename, bool is_replay)
ep3_card_auction_points(0),
ep3_card_auction_min_size(0),
ep3_card_auction_max_size(0),
player_files_manager(make_shared<PlayerFilesManager>(base)),
next_lobby_id(1),
pre_lobby_event(0),
ep3_menu_song(-1),
+4 -1
View File
@@ -1,5 +1,7 @@
#pragma once
#include <event2/event.h>
#include <atomic>
#include <map>
#include <memory>
@@ -167,6 +169,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::string pc_patch_server_message;
std::string bb_patch_server_message;
std::shared_ptr<PlayerFilesManager> player_files_manager;
std::unordered_map<Channel*, std::shared_ptr<Client>> channel_to_client;
std::map<int64_t, std::shared_ptr<Lobby>> id_to_lobby;
std::vector<std::shared_ptr<Lobby>> public_lobby_search_order;
@@ -184,7 +187,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::shared_ptr<ProxyServer> proxy_server;
std::shared_ptr<Server> game_server;
ServerState(const std::string& config_filename, bool is_replay);
ServerState(std::shared_ptr<struct event_base> base, const std::string& config_filename, bool is_replay);
ServerState(const ServerState&) = delete;
ServerState(ServerState&&) = delete;
ServerState& operator=(const ServerState&) = delete;