160 lines
4.8 KiB
C++
160 lines
4.8 KiB
C++
#include "Client.hh"
|
|
|
|
#include <errno.h>
|
|
#include <event2/buffer.h>
|
|
#include <event2/bufferevent.h>
|
|
#include <event2/event.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <atomic>
|
|
#include <phosg/Network.hh>
|
|
#include <phosg/Time.hh>
|
|
|
|
#include "Loggers.hh"
|
|
#include "Version.hh"
|
|
|
|
using namespace std;
|
|
|
|
const uint64_t CLIENT_CONFIG_MAGIC = 0x492A890E82AC9839;
|
|
|
|
static atomic<uint64_t> next_id(1);
|
|
|
|
ClientOptions::ClientOptions()
|
|
: switch_assist(false),
|
|
infinite_hp(false),
|
|
infinite_tp(false),
|
|
debug(false),
|
|
override_section_id(-1),
|
|
override_lobby_event(-1),
|
|
override_lobby_number(-1),
|
|
override_random_seed(-1),
|
|
save_files(false),
|
|
enable_chat_commands(true),
|
|
enable_chat_filter(true),
|
|
enable_player_notifications(false),
|
|
suppress_client_pings(false),
|
|
suppress_remote_login(false),
|
|
zero_remote_guild_card(false),
|
|
ep3_infinite_meseta(false),
|
|
red_name(false),
|
|
blank_name(false),
|
|
function_call_return_value(-1) {}
|
|
|
|
Client::Client(
|
|
struct bufferevent* bev,
|
|
GameVersion version,
|
|
ServerBehavior server_behavior)
|
|
: id(next_id++),
|
|
log(string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level),
|
|
bb_game_state(0),
|
|
flags(flags_for_version(version, -1)),
|
|
specific_version(default_specific_version_for_version(version, -1)),
|
|
channel(bev, version, nullptr, nullptr, this, string_printf("C-%" PRIX64, this->id), TerminalFormat::FG_YELLOW, TerminalFormat::FG_GREEN),
|
|
server_behavior(server_behavior),
|
|
should_disconnect(false),
|
|
should_send_to_lobby_server(false),
|
|
should_send_to_proxy_server(false),
|
|
proxy_destination_address(0),
|
|
proxy_destination_port(0),
|
|
x(0.0f),
|
|
z(0.0f),
|
|
area(0),
|
|
lobby_id(0),
|
|
lobby_client_id(0),
|
|
lobby_arrow_color(0),
|
|
preferred_lobby_id(-1),
|
|
save_game_data_event(
|
|
event_new(
|
|
bufferevent_get_base(bev), -1, EV_TIMEOUT | EV_PERSIST,
|
|
&Client::dispatch_save_game_data, this),
|
|
event_free),
|
|
card_battle_table_number(-1),
|
|
card_battle_table_seat_number(0),
|
|
card_battle_table_seat_state(0),
|
|
next_exp_value(0),
|
|
can_chat(true),
|
|
pending_bb_save_player_index(0),
|
|
dol_base_addr(0) {
|
|
this->last_switch_enabled_command.header.subcommand = 0;
|
|
memset(&this->next_connection_addr, 0, sizeof(this->next_connection_addr));
|
|
|
|
if (this->version() == GameVersion::BB) {
|
|
struct timeval tv = usecs_to_timeval(60000000); // 1 minute
|
|
event_add(this->save_game_data_event.get(), &tv);
|
|
}
|
|
|
|
this->log.info("Created");
|
|
}
|
|
|
|
Client::~Client() {
|
|
if (!this->disconnect_hooks.empty()) {
|
|
this->log.warning("Disconnect hooks pending at client destruction time:");
|
|
for (const auto& it : this->disconnect_hooks) {
|
|
this->log.warning(" %s", it.first.c_str());
|
|
}
|
|
}
|
|
|
|
this->log.info("Deleted");
|
|
}
|
|
|
|
void Client::set_license(shared_ptr<const License> l) {
|
|
this->license = l;
|
|
this->game_data.guild_card_number = this->license->serial_number;
|
|
if (this->version() == GameVersion::BB) {
|
|
this->game_data.bb_username = this->license->username;
|
|
}
|
|
}
|
|
|
|
ClientConfig Client::export_config() const {
|
|
ClientConfig cc;
|
|
cc.magic = CLIENT_CONFIG_MAGIC;
|
|
cc.flags = this->flags;
|
|
cc.specific_version = this->specific_version;
|
|
cc.proxy_destination_address = this->proxy_destination_address;
|
|
cc.proxy_destination_port = this->proxy_destination_port;
|
|
cc.unused.clear(0xFF);
|
|
return cc;
|
|
}
|
|
|
|
ClientConfigBB Client::export_config_bb() const {
|
|
ClientConfigBB cc;
|
|
cc.cfg = this->export_config();
|
|
cc.bb_game_state = this->bb_game_state;
|
|
cc.bb_player_index = this->game_data.bb_player_index;
|
|
cc.unused.clear(0xFF);
|
|
return cc;
|
|
}
|
|
|
|
void Client::import_config(const ClientConfig& cc) {
|
|
if (cc.magic != CLIENT_CONFIG_MAGIC) {
|
|
throw invalid_argument("invalid client config");
|
|
}
|
|
this->flags = cc.flags;
|
|
this->specific_version = cc.specific_version;
|
|
this->proxy_destination_address = cc.proxy_destination_address;
|
|
this->proxy_destination_port = cc.proxy_destination_port;
|
|
}
|
|
|
|
void Client::import_config(const ClientConfigBB& cc) {
|
|
this->import_config(cc.cfg);
|
|
this->bb_game_state = cc.bb_game_state;
|
|
this->game_data.bb_player_index = cc.bb_player_index;
|
|
}
|
|
|
|
void Client::dispatch_save_game_data(evutil_socket_t, short, void* ctx) {
|
|
reinterpret_cast<Client*>(ctx)->save_game_data();
|
|
}
|
|
|
|
void Client::save_game_data() {
|
|
if (this->version() != GameVersion::BB) {
|
|
throw logic_error("save_game_data called for non-BB client");
|
|
}
|
|
if (this->game_data.account(false)) {
|
|
this->game_data.save_account_data();
|
|
}
|
|
if (this->game_data.player(false)) {
|
|
this->game_data.save_player_data();
|
|
}
|
|
}
|