cache loaded player files between sessions
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user