move HTTP server to separate thread
This commit is contained in:
@@ -4,5 +4,31 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::function<void()>&& fn);
|
void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::function<void()>&& fn);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T call_on_event_thread(std::shared_ptr<struct event_base> base, std::function<T()>&& compute) {
|
||||||
|
std::optional<T> ret;
|
||||||
|
std::string exc_what;
|
||||||
|
std::mutex ret_lock;
|
||||||
|
std::condition_variable ret_cv;
|
||||||
|
std::unique_lock<std::mutex> g(ret_lock);
|
||||||
|
forward_to_event_thread(base, [&]() -> void {
|
||||||
|
std::lock_guard<std::mutex> g(ret_lock);
|
||||||
|
try {
|
||||||
|
ret = compute();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
exc_what = e.what();
|
||||||
|
}
|
||||||
|
ret_cv.notify_one();
|
||||||
|
});
|
||||||
|
ret_cv.wait(g);
|
||||||
|
if (!ret.has_value()) {
|
||||||
|
throw std::runtime_error(exc_what);
|
||||||
|
}
|
||||||
|
return ret.value();
|
||||||
|
}
|
||||||
|
|||||||
+183
-145
@@ -10,6 +10,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "EventUtils.hh"
|
||||||
#include "Loggers.hh"
|
#include "Loggers.hh"
|
||||||
#include "ProxyServer.hh"
|
#include "ProxyServer.hh"
|
||||||
#include "Server.hh"
|
#include "Server.hh"
|
||||||
@@ -164,7 +165,9 @@ const string& HTTPServer::get_url_param(
|
|||||||
|
|
||||||
HTTPServer::HTTPServer(shared_ptr<ServerState> state)
|
HTTPServer::HTTPServer(shared_ptr<ServerState> state)
|
||||||
: state(state),
|
: state(state),
|
||||||
http(evhttp_new(this->state->base.get()), evhttp_free) {
|
base(event_base_new(), event_base_free),
|
||||||
|
http(evhttp_new(this->base.get()), evhttp_free),
|
||||||
|
th(&HTTPServer::thread_fn, this) {
|
||||||
evhttp_set_gencb(this->http.get(), this->dispatch_handle_request, this);
|
evhttp_set_gencb(this->http.get(), this->dispatch_handle_request, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,11 +196,19 @@ void HTTPServer::add_socket(int fd) {
|
|||||||
evhttp_accept_socket(this->http.get(), fd);
|
evhttp_accept_socket(this->http.get(), fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPServer::schedule_stop() {
|
||||||
|
event_base_loopexit(this->base.get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::wait_for_stop() {
|
||||||
|
this->th.join();
|
||||||
|
}
|
||||||
|
|
||||||
void HTTPServer::dispatch_handle_request(struct evhttp_request* req, void* ctx) {
|
void HTTPServer::dispatch_handle_request(struct evhttp_request* req, void* ctx) {
|
||||||
reinterpret_cast<HTTPServer*>(ctx)->handle_request(req);
|
reinterpret_cast<HTTPServer*>(ctx)->handle_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_quest_json(shared_ptr<const Quest> q) const {
|
JSON HTTPServer::generate_quest_json_st(shared_ptr<const Quest> q) {
|
||||||
if (!q) {
|
if (!q) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -215,7 +226,7 @@ JSON HTTPServer::generate_quest_json(shared_ptr<const Quest> q) const {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_client_config_json(const Client::Config& config) const {
|
JSON HTTPServer::generate_client_config_json_st(const Client::Config& config) {
|
||||||
const char* drop_notifications_mode = "unknown";
|
const char* drop_notifications_mode = "unknown";
|
||||||
switch (config.get_drop_notification_mode()) {
|
switch (config.get_drop_notification_mode()) {
|
||||||
case Client::ItemDropNotificationMode::NOTHING:
|
case Client::ItemDropNotificationMode::NOTHING:
|
||||||
@@ -255,7 +266,7 @@ JSON HTTPServer::generate_client_config_json(const Client::Config& config) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_license_json(shared_ptr<const License> l) const {
|
JSON HTTPServer::generate_license_json_st(shared_ptr<const License> l) {
|
||||||
auto ret = JSON::dict({
|
auto ret = JSON::dict({
|
||||||
{"SerialNumber", l->serial_number},
|
{"SerialNumber", l->serial_number},
|
||||||
{"Flags", l->flags},
|
{"Flags", l->flags},
|
||||||
@@ -270,20 +281,20 @@ JSON HTTPServer::generate_license_json(shared_ptr<const License> l) const {
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
JSON HTTPServer::generate_game_client_json(shared_ptr<const Client> c) const {
|
JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared_ptr<const ItemNameIndex> item_name_index) {
|
||||||
auto ret = JSON::dict({
|
auto ret = JSON::dict({
|
||||||
{"ID", c->id},
|
{"ID", c->id},
|
||||||
{"RemoteAddress", render_sockaddr_storage(c->channel.remote_addr)},
|
{"RemoteAddress", render_sockaddr_storage(c->channel.remote_addr)},
|
||||||
{"Version", name_for_enum(c->version())},
|
{"Version", name_for_enum(c->version())},
|
||||||
{"SubVersion", c->sub_version},
|
{"SubVersion", c->sub_version},
|
||||||
{"Config", this->generate_client_config_json(c->config)},
|
{"Config", HTTPServer::generate_client_config_json_st(c->config)},
|
||||||
{"Language", name_for_language_code(c->language())},
|
{"Language", name_for_language_code(c->language())},
|
||||||
{"LocationX", c->x},
|
{"LocationX", c->x},
|
||||||
{"LocationZ", c->z},
|
{"LocationZ", c->z},
|
||||||
{"LocationFloor", c->floor},
|
{"LocationFloor", c->floor},
|
||||||
{"CanChat", c->can_chat},
|
{"CanChat", c->can_chat},
|
||||||
});
|
});
|
||||||
ret.emplace("license", c->license ? this->generate_license_json(c->license) : JSON(nullptr));
|
ret.emplace("license", c->license ? HTTPServer::generate_license_json_st(c->license) : JSON(nullptr));
|
||||||
auto l = c->lobby.lock();
|
auto l = c->lobby.lock();
|
||||||
if (l) {
|
if (l) {
|
||||||
ret.emplace("LobbyID", l->lobby_id);
|
ret.emplace("LobbyID", l->lobby_id);
|
||||||
@@ -311,14 +322,14 @@ JSON HTTPServer::generate_game_client_json(shared_ptr<const Client> c) const {
|
|||||||
JSON items_json = JSON::list();
|
JSON items_json = JSON::list();
|
||||||
for (size_t z = 0; z < p->inventory.num_items; z++) {
|
for (size_t z = 0; z < p->inventory.num_items; z++) {
|
||||||
const auto& item = p->inventory.items[z];
|
const auto& item = p->inventory.items[z];
|
||||||
string description = this->state->describe_item(c->version(), item.data, false);
|
|
||||||
string data_str = item.data.hex();
|
|
||||||
auto item_dict = JSON::dict({
|
auto item_dict = JSON::dict({
|
||||||
{"Flags", item.flags.load()},
|
{"Flags", item.flags.load()},
|
||||||
{"Data", std::move(data_str)},
|
{"Data", item.data.hex()},
|
||||||
{"Description", std::move(description)},
|
|
||||||
{"ItemID", item.data.id.load()},
|
{"ItemID", item.data.id.load()},
|
||||||
});
|
});
|
||||||
|
if (item_name_index) {
|
||||||
|
item_dict.emplace("Description", item_name_index->describe_item(item.data, false));
|
||||||
|
}
|
||||||
items_json.emplace_back(std::move(item_dict));
|
items_json.emplace_back(std::move(item_dict));
|
||||||
}
|
}
|
||||||
ret.emplace("ATP", p->disp.stats.char_stats.atp.load());
|
ret.emplace("ATP", p->disp.stats.char_stats.atp.load());
|
||||||
@@ -419,7 +430,7 @@ JSON HTTPServer::generate_game_client_json(shared_ptr<const Client> c) const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_proxy_client_json(shared_ptr<const ProxyServer::LinkedSession> ses) const {
|
JSON HTTPServer::generate_proxy_client_json_st(shared_ptr<const ProxyServer::LinkedSession> ses) {
|
||||||
struct LobbyPlayer {
|
struct LobbyPlayer {
|
||||||
uint32_t guild_card_number = 0;
|
uint32_t guild_card_number = 0;
|
||||||
uint64_t xb_user_id = 0;
|
uint64_t xb_user_id = 0;
|
||||||
@@ -459,7 +470,7 @@ JSON HTTPServer::generate_proxy_client_json(shared_ptr<const ProxyServer::Linked
|
|||||||
{"DCHardwareID", ses->hardware_id},
|
{"DCHardwareID", ses->hardware_id},
|
||||||
{"RemoteGuildCardNumber", ses->remote_guild_card_number},
|
{"RemoteGuildCardNumber", ses->remote_guild_card_number},
|
||||||
{"RemoteClientConfigData", format_data_string(&ses->remote_client_config_data[0], ses->remote_client_config_data.size())},
|
{"RemoteClientConfigData", format_data_string(&ses->remote_client_config_data[0], ses->remote_client_config_data.size())},
|
||||||
{"Config", this->generate_client_config_json(ses->config)},
|
{"Config", HTTPServer::generate_client_config_json_st(ses->config)},
|
||||||
{"Language", name_for_language_code(ses->language())},
|
{"Language", name_for_language_code(ses->language())},
|
||||||
{"LobbyClientID", ses->lobby_client_id},
|
{"LobbyClientID", ses->lobby_client_id},
|
||||||
{"LeaderClientID", ses->leader_client_id},
|
{"LeaderClientID", ses->leader_client_id},
|
||||||
@@ -487,11 +498,11 @@ JSON HTTPServer::generate_proxy_client_json(shared_ptr<const ProxyServer::Linked
|
|||||||
ret.emplace("DropMode", "proxy");
|
ret.emplace("DropMode", "proxy");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret.emplace("License", ses->license ? this->generate_license_json(ses->license) : JSON(nullptr));
|
ret.emplace("License", ses->license ? HTTPServer::generate_license_json_st(ses->license) : JSON(nullptr));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_lobby_json(shared_ptr<const Lobby> l) const {
|
JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<const ItemNameIndex> item_name_index) {
|
||||||
std::array<std::shared_ptr<Client>, 12> clients;
|
std::array<std::shared_ptr<Client>, 12> clients;
|
||||||
|
|
||||||
auto client_ids_json = JSON::list();
|
auto client_ids_json = JSON::list();
|
||||||
@@ -569,23 +580,23 @@ JSON HTTPServer::generate_lobby_json(shared_ptr<const Lobby> l) const {
|
|||||||
for (size_t floor = 0; floor < l->floor_item_managers.size(); floor++) {
|
for (size_t floor = 0; floor < l->floor_item_managers.size(); floor++) {
|
||||||
for (const auto& it : l->floor_item_managers[floor].items) {
|
for (const auto& it : l->floor_item_managers[floor].items) {
|
||||||
const auto& item = it.second;
|
const auto& item = it.second;
|
||||||
string description = this->state->describe_item(l->base_version, item->data, false);
|
|
||||||
string data_str = item->data.hex();
|
|
||||||
auto item_dict = JSON::dict({
|
auto item_dict = JSON::dict({
|
||||||
{"LocationFloor", floor},
|
{"LocationFloor", floor},
|
||||||
{"LocationX", item->x},
|
{"LocationX", item->x},
|
||||||
{"LocationZ", item->z},
|
{"LocationZ", item->z},
|
||||||
{"DropNumber", item->drop_number},
|
{"DropNumber", item->drop_number},
|
||||||
{"VisibilityFlags", item->visibility_flags},
|
{"VisibilityFlags", item->visibility_flags},
|
||||||
{"Data", std::move(data_str)},
|
{"Data", item->data.hex()},
|
||||||
{"Description", std::move(description)},
|
|
||||||
{"ItemID", item->data.id.load()},
|
{"ItemID", item->data.id.load()},
|
||||||
});
|
});
|
||||||
|
if (item_name_index) {
|
||||||
|
item_dict.emplace("Description", item_name_index->describe_item(item->data, false));
|
||||||
|
}
|
||||||
floor_items_json.emplace_back(std::move(item_dict));
|
floor_items_json.emplace_back(std::move(item_dict));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.emplace("FloorItems", std::move(floor_items_json));
|
ret.emplace("FloorItems", std::move(floor_items_json));
|
||||||
ret.emplace("Quest", this->generate_quest_json(l->quest));
|
ret.emplace("Quest", HTTPServer::generate_quest_json_st(l->quest));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ret.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS));
|
ret.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS));
|
||||||
@@ -691,119 +702,130 @@ JSON HTTPServer::generate_lobby_json(shared_ptr<const Lobby> l) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_game_server_clients_json() const {
|
JSON HTTPServer::generate_game_server_clients_json() const {
|
||||||
JSON res = JSON::list();
|
return call_on_event_thread<JSON>(this->state->base, [&]() {
|
||||||
for (const auto& it : this->state->channel_to_client) {
|
auto res = JSON::list();
|
||||||
res.emplace_back(this->generate_game_client_json(it.second));
|
for (const auto& it : this->state->channel_to_client) {
|
||||||
}
|
res.emplace_back(this->generate_game_client_json_st(it.second, this->state->item_name_index_opt(it.second->version())));
|
||||||
return res;
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_proxy_server_clients_json() const {
|
JSON HTTPServer::generate_proxy_server_clients_json() const {
|
||||||
JSON res = JSON::list();
|
return call_on_event_thread<JSON>(this->state->base, [&]() {
|
||||||
for (const auto& it : this->state->proxy_server->all_sessions()) {
|
JSON res = JSON::list();
|
||||||
res.emplace_back(this->generate_proxy_client_json(it.second));
|
for (const auto& it : this->state->proxy_server->all_sessions()) {
|
||||||
}
|
res.emplace_back(this->generate_proxy_client_json_st(it.second));
|
||||||
return res;
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_server_info_json() const {
|
JSON HTTPServer::generate_server_info_json() const {
|
||||||
size_t game_count = 0;
|
return call_on_event_thread<JSON>(this->state->base, [&]() {
|
||||||
size_t lobby_count = 0;
|
size_t game_count = 0;
|
||||||
for (const auto& it : this->state->id_to_lobby) {
|
size_t lobby_count = 0;
|
||||||
if (it.second->is_game()) {
|
for (const auto& it : this->state->id_to_lobby) {
|
||||||
game_count++;
|
if (it.second->is_game()) {
|
||||||
} else {
|
game_count++;
|
||||||
lobby_count++;
|
} else {
|
||||||
|
lobby_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
uint64_t uptime_usecs = now() - this->state->creation_time;
|
||||||
uint64_t uptime_usecs = now() - this->state->creation_time;
|
return JSON::dict({
|
||||||
return JSON::dict({
|
{"StartTimeUsecs", this->state->creation_time},
|
||||||
{"StartTimeUsecs", this->state->creation_time},
|
{"StartTime", format_time(this->state->creation_time)},
|
||||||
{"StartTime", format_time(this->state->creation_time)},
|
{"UptimeUsecs", uptime_usecs},
|
||||||
{"UptimeUsecs", uptime_usecs},
|
{"Uptime", format_duration(uptime_usecs)},
|
||||||
{"Uptime", format_duration(uptime_usecs)},
|
{"LobbyCount", lobby_count},
|
||||||
{"LobbyCount", lobby_count},
|
{"GameCount", game_count},
|
||||||
{"GameCount", game_count},
|
{"ClientCount", this->state->channel_to_client.size()},
|
||||||
{"ClientCount", this->state->channel_to_client.size()},
|
{"ProxySessionCount", this->state->proxy_server->num_sessions()},
|
||||||
{"ProxySessionCount", this->state->proxy_server->num_sessions()},
|
{"ServerName", this->state->name},
|
||||||
{"ServerName", this->state->name},
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_lobbies_json() const {
|
JSON HTTPServer::generate_lobbies_json() const {
|
||||||
JSON res = JSON::list();
|
return call_on_event_thread<JSON>(this->state->base, [&]() {
|
||||||
for (const auto& it : this->state->id_to_lobby) {
|
JSON res = JSON::list();
|
||||||
res.emplace_back(this->generate_lobby_json(it.second));
|
for (const auto& it : this->state->id_to_lobby) {
|
||||||
}
|
res.emplace_back(this->generate_lobby_json_st(it.second, this->state->item_name_index_opt(it.second->base_version)));
|
||||||
return res;
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_summary_json() const {
|
JSON HTTPServer::generate_summary_json() const {
|
||||||
auto clients_json = JSON::list();
|
auto ret = call_on_event_thread<JSON>(this->state->base, [&]() {
|
||||||
for (const auto& it : this->state->channel_to_client) {
|
auto clients_json = JSON::list();
|
||||||
auto c = it.second;
|
for (const auto& it : this->state->channel_to_client) {
|
||||||
auto p = c->character(false, false);
|
auto c = it.second;
|
||||||
auto l = c->lobby.lock();
|
auto p = c->character(false, false);
|
||||||
clients_json.emplace_back(JSON::dict({
|
auto l = c->lobby.lock();
|
||||||
{"ID", c->id},
|
clients_json.emplace_back(JSON::dict({
|
||||||
{"SerialNumber", c->license ? c->license->serial_number : JSON(nullptr)},
|
{"ID", c->id},
|
||||||
{"Name", p ? p->disp.name.decode(it.second->language()) : JSON(nullptr)},
|
{"SerialNumber", c->license ? c->license->serial_number : JSON(nullptr)},
|
||||||
{"Version", name_for_enum(it.second->version())},
|
{"Name", p ? p->disp.name.decode(it.second->language()) : JSON(nullptr)},
|
||||||
{"Language", name_for_language_code(it.second->language())},
|
{"Version", name_for_enum(it.second->version())},
|
||||||
{"Level", p ? p->disp.stats.level + 1 : JSON(nullptr)},
|
{"Language", name_for_language_code(it.second->language())},
|
||||||
{"Class", p ? name_for_char_class(p->disp.visual.char_class) : JSON(nullptr)},
|
{"Level", p ? p->disp.stats.level + 1 : JSON(nullptr)},
|
||||||
{"SectionID", p ? name_for_section_id(p->disp.visual.section_id) : JSON(nullptr)},
|
{"Class", p ? name_for_char_class(p->disp.visual.char_class) : JSON(nullptr)},
|
||||||
{"LobbyID", l ? l->lobby_id : JSON(nullptr)},
|
{"SectionID", p ? name_for_section_id(p->disp.visual.section_id) : JSON(nullptr)},
|
||||||
}));
|
{"LobbyID", l ? l->lobby_id : JSON(nullptr)},
|
||||||
}
|
}));
|
||||||
|
|
||||||
auto proxy_clients_json = JSON::list();
|
|
||||||
for (const auto& it : this->state->proxy_server->all_sessions()) {
|
|
||||||
proxy_clients_json.emplace_back(JSON::dict({
|
|
||||||
{"SerialNumber", it.second->license ? it.second->license->serial_number : JSON(nullptr)},
|
|
||||||
{"Name", it.second->character_name},
|
|
||||||
{"Version", name_for_enum(it.second->version())},
|
|
||||||
{"Language", name_for_language_code(it.second->language())},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto games_json = JSON::list();
|
|
||||||
for (const auto& it : this->state->id_to_lobby) {
|
|
||||||
auto l = it.second;
|
|
||||||
if (l->is_game()) {
|
|
||||||
auto game_json = JSON::dict({
|
|
||||||
{"ID", l->lobby_id},
|
|
||||||
{"Name", l->name},
|
|
||||||
{"BaseVersion", name_for_enum(l->base_version)},
|
|
||||||
{"Players", l->count_clients()},
|
|
||||||
{"CheatsEnabled", l->check_flag(Lobby::Flag::CHEATS_ENABLED)},
|
|
||||||
{"Episode", name_for_episode(l->episode)},
|
|
||||||
{"HasPassword", !l->password.empty()},
|
|
||||||
});
|
|
||||||
if (l->episode == Episode::EP3) {
|
|
||||||
auto ep3s = l->ep3_server;
|
|
||||||
game_json.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS));
|
|
||||||
game_json.emplace("IsSpectatorTeam", l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM));
|
|
||||||
game_json.emplace("MapNumber", (ep3s && ep3s->last_chosen_map) ? ep3s->last_chosen_map->map_number : JSON(nullptr));
|
|
||||||
game_json.emplace("Rules", (ep3s && ep3s->map_and_rules) ? ep3s->map_and_rules->rules.json() : nullptr);
|
|
||||||
} else {
|
|
||||||
game_json.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS));
|
|
||||||
game_json.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS));
|
|
||||||
game_json.emplace("SectionID", name_for_section_id(l->section_id));
|
|
||||||
game_json.emplace("Mode", name_for_mode(l->mode));
|
|
||||||
game_json.emplace("Difficulty", name_for_difficulty(l->difficulty));
|
|
||||||
game_json.emplace("Quest", this->generate_quest_json(l->quest));
|
|
||||||
}
|
|
||||||
games_json.emplace_back(std::move(game_json));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return JSON::dict({
|
auto proxy_clients_json = JSON::list();
|
||||||
{"Clients", std::move(clients_json)},
|
for (const auto& it : this->state->proxy_server->all_sessions()) {
|
||||||
{"ProxyClients", std::move(proxy_clients_json)},
|
proxy_clients_json.emplace_back(JSON::dict({
|
||||||
{"Games", std::move(games_json)},
|
{"SerialNumber", it.second->license ? it.second->license->serial_number : JSON(nullptr)},
|
||||||
{"Server", this->generate_server_info_json()},
|
{"Name", it.second->character_name},
|
||||||
|
{"Version", name_for_enum(it.second->version())},
|
||||||
|
{"Language", name_for_language_code(it.second->language())},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto games_json = JSON::list();
|
||||||
|
for (const auto& it : this->state->id_to_lobby) {
|
||||||
|
auto l = it.second;
|
||||||
|
if (l->is_game()) {
|
||||||
|
auto game_json = JSON::dict({
|
||||||
|
{"ID", l->lobby_id},
|
||||||
|
{"Name", l->name},
|
||||||
|
{"BaseVersion", name_for_enum(l->base_version)},
|
||||||
|
{"Players", l->count_clients()},
|
||||||
|
{"CheatsEnabled", l->check_flag(Lobby::Flag::CHEATS_ENABLED)},
|
||||||
|
{"Episode", name_for_episode(l->episode)},
|
||||||
|
{"HasPassword", !l->password.empty()},
|
||||||
|
});
|
||||||
|
if (l->episode == Episode::EP3) {
|
||||||
|
auto ep3s = l->ep3_server;
|
||||||
|
game_json.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS));
|
||||||
|
game_json.emplace("IsSpectatorTeam", l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM));
|
||||||
|
game_json.emplace("MapNumber", (ep3s && ep3s->last_chosen_map) ? ep3s->last_chosen_map->map_number : JSON(nullptr));
|
||||||
|
game_json.emplace("Rules", (ep3s && ep3s->map_and_rules) ? ep3s->map_and_rules->rules.json() : nullptr);
|
||||||
|
} else {
|
||||||
|
game_json.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS));
|
||||||
|
game_json.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS));
|
||||||
|
game_json.emplace("SectionID", name_for_section_id(l->section_id));
|
||||||
|
game_json.emplace("Mode", name_for_mode(l->mode));
|
||||||
|
game_json.emplace("Difficulty", name_for_difficulty(l->difficulty));
|
||||||
|
game_json.emplace("Quest", this->generate_quest_json_st(l->quest));
|
||||||
|
}
|
||||||
|
games_json.emplace_back(std::move(game_json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON::dict({
|
||||||
|
{"Clients", std::move(clients_json)},
|
||||||
|
{"ProxyClients", std::move(proxy_clients_json)},
|
||||||
|
{"Games", std::move(games_json)},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
ret.emplace("Server", this->generate_server_info_json());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_all_json() const {
|
JSON HTTPServer::generate_all_json() const {
|
||||||
@@ -816,13 +838,18 @@ JSON HTTPServer::generate_all_json() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_ep3_cards_json(bool trial) const {
|
JSON HTTPServer::generate_ep3_cards_json(bool trial) const {
|
||||||
const auto& index = trial ? this->state->ep3_card_index_trial : this->state->ep3_card_index;
|
auto index = call_on_event_thread<shared_ptr<const Episode3::CardIndex>>(this->state->base, [&]() {
|
||||||
|
return trial ? this->state->ep3_card_index_trial : this->state->ep3_card_index;
|
||||||
|
});
|
||||||
return index->definitions_json();
|
return index->definitions_json();
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON HTTPServer::generate_rare_tables_json() const {
|
JSON HTTPServer::generate_rare_tables_json() const {
|
||||||
|
auto sets = call_on_event_thread<unordered_map<string, shared_ptr<const RareItemSet>>>(this->state->base, [&]() {
|
||||||
|
return this->state->rare_item_sets;
|
||||||
|
});
|
||||||
JSON ret = JSON::list();
|
JSON ret = JSON::list();
|
||||||
for (const auto& it : this->state->rare_item_sets) {
|
for (const auto& it : sets) {
|
||||||
ret.emplace_back(it.first);
|
ret.emplace_back(it.first);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -830,25 +857,28 @@ JSON HTTPServer::generate_rare_tables_json() const {
|
|||||||
|
|
||||||
JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
|
JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
|
||||||
try {
|
try {
|
||||||
const auto& table = this->state->rare_item_sets.at(table_name);
|
auto colls = call_on_event_thread<pair<shared_ptr<const RareItemSet>, shared_ptr<const ItemNameIndex>>>(this->state->base, [&]() {
|
||||||
shared_ptr<const ItemNameIndex> name_index;
|
const auto& table = this->state->rare_item_sets.at(table_name);
|
||||||
if (ends_with(table_name, "-v1")) {
|
shared_ptr<const ItemNameIndex> name_index;
|
||||||
name_index = this->state->item_name_index(Version::DC_V1);
|
if (ends_with(table_name, "-v1")) {
|
||||||
} else if (ends_with(table_name, "-v2")) {
|
name_index = this->state->item_name_index_opt(Version::DC_V1);
|
||||||
name_index = this->state->item_name_index(Version::PC_V2);
|
} else if (ends_with(table_name, "-v2")) {
|
||||||
} else if (ends_with(table_name, "-v3")) {
|
name_index = this->state->item_name_index_opt(Version::PC_V2);
|
||||||
name_index = this->state->item_name_index(Version::GC_V3);
|
} else if (ends_with(table_name, "-v3")) {
|
||||||
} else if (ends_with(table_name, "-v4")) {
|
name_index = this->state->item_name_index_opt(Version::GC_V3);
|
||||||
name_index = this->state->item_name_index(Version::BB_V4);
|
} else if (ends_with(table_name, "-v4")) {
|
||||||
}
|
name_index = this->state->item_name_index_opt(Version::BB_V4);
|
||||||
return table->json(name_index);
|
}
|
||||||
|
return make_pair(table, name_index);
|
||||||
|
});
|
||||||
|
return colls.first->json(colls.second);
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
throw http_error(404, "table does not exist");
|
throw http_error(404, "table does not exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPServer::handle_request(struct evhttp_request* req) {
|
void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||||
JSON ret;
|
shared_ptr<const JSON> ret;
|
||||||
uint32_t serialize_options = 0;
|
uint32_t serialize_options = 0;
|
||||||
try {
|
try {
|
||||||
string uri = evhttp_request_get_uri(req);
|
string uri = evhttp_request_get_uri(req);
|
||||||
@@ -862,7 +892,10 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
|||||||
|
|
||||||
static const string default_format_option = "false";
|
static const string default_format_option = "false";
|
||||||
if (this->get_url_param(query, "format", &default_format_option) == "true") {
|
if (this->get_url_param(query, "format", &default_format_option) == "true") {
|
||||||
serialize_options = JSON::SerializeOption::FORMAT | JSON::SerializeOption::SORT_DICT_KEYS;
|
serialize_options |= JSON::SerializeOption::FORMAT | JSON::SerializeOption::SORT_DICT_KEYS;
|
||||||
|
}
|
||||||
|
if (this->get_url_param(query, "hex", &default_format_option) == "true") {
|
||||||
|
serialize_options |= JSON::SerializeOption::HEX_INTEGERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri == "/") {
|
if (uri == "/") {
|
||||||
@@ -870,6 +903,7 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
|||||||
"/y/data/ep3-cards",
|
"/y/data/ep3-cards",
|
||||||
"/y/data/ep3-cards-trial",
|
"/y/data/ep3-cards-trial",
|
||||||
"/y/data/rare-tables",
|
"/y/data/rare-tables",
|
||||||
|
"/y/data/rare-tables/<TABLE-NAME>",
|
||||||
"/y/data/config",
|
"/y/data/config",
|
||||||
"/y/clients",
|
"/y/clients",
|
||||||
"/y/proxy-clients",
|
"/y/proxy-clients",
|
||||||
@@ -878,30 +912,30 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
|||||||
"/y/summary",
|
"/y/summary",
|
||||||
"/y/all",
|
"/y/all",
|
||||||
});
|
});
|
||||||
ret = JSON::dict({{"endpoints", std::move(endpoints_json)}});
|
ret = make_shared<JSON>(JSON::dict({{"endpoints", std::move(endpoints_json)}}));
|
||||||
|
|
||||||
} else if (uri == "/y/data/ep3-cards") {
|
} else if (uri == "/y/data/ep3-cards") {
|
||||||
ret = this->generate_ep3_cards_json(false);
|
ret = make_shared<JSON>(this->generate_ep3_cards_json(false));
|
||||||
} else if (uri == "/y/data/ep3-cards-trial") {
|
} else if (uri == "/y/data/ep3-cards-trial") {
|
||||||
ret = this->generate_ep3_cards_json(true);
|
ret = make_shared<JSON>(this->generate_ep3_cards_json(true));
|
||||||
} else if (uri == "/y/data/rare-tables") {
|
} else if (uri == "/y/data/rare-tables") {
|
||||||
ret = this->generate_rare_tables_json();
|
ret = make_shared<JSON>(this->generate_rare_tables_json());
|
||||||
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
|
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
|
||||||
ret = this->generate_rare_table_json(uri.substr(20));
|
ret = make_shared<JSON>(this->generate_rare_table_json(uri.substr(20)));
|
||||||
} else if (uri == "/y/data/config") {
|
} else if (uri == "/y/data/config") {
|
||||||
ret = this->state->config_json;
|
ret = call_on_event_thread<shared_ptr<const JSON>>(this->state->base, [this]() { return this->state->config_json; });
|
||||||
} else if (uri == "/y/clients") {
|
} else if (uri == "/y/clients") {
|
||||||
ret = this->generate_game_server_clients_json();
|
ret = make_shared<JSON>(this->generate_game_server_clients_json());
|
||||||
} else if (uri == "/y/proxy-clients") {
|
} else if (uri == "/y/proxy-clients") {
|
||||||
ret = this->generate_proxy_server_clients_json();
|
ret = make_shared<JSON>(this->generate_proxy_server_clients_json());
|
||||||
} else if (uri == "/y/lobbies") {
|
} else if (uri == "/y/lobbies") {
|
||||||
ret = this->generate_lobbies_json();
|
ret = make_shared<JSON>(this->generate_lobbies_json());
|
||||||
} else if (uri == "/y/server") {
|
} else if (uri == "/y/server") {
|
||||||
ret = this->generate_server_info_json();
|
ret = make_shared<JSON>(this->generate_server_info_json());
|
||||||
} else if (uri == "/y/summary") {
|
} else if (uri == "/y/summary") {
|
||||||
ret = this->generate_summary_json();
|
ret = make_shared<JSON>(this->generate_summary_json());
|
||||||
} else if (uri == "/y/all") {
|
} else if (uri == "/y/all") {
|
||||||
ret = this->generate_all_json();
|
ret = make_shared<JSON>(this->generate_all_json());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw http_error(404, "unknown action");
|
throw http_error(404, "unknown action");
|
||||||
@@ -922,10 +956,14 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free);
|
unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free);
|
||||||
string* serialized = new string(ret.serialize(JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options));
|
string* serialized = new string(ret->serialize(JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options));
|
||||||
auto cleanup = +[](const void*, size_t, void* s) -> void {
|
auto cleanup = +[](const void*, size_t, void* s) -> void {
|
||||||
delete reinterpret_cast<string*>(s);
|
delete reinterpret_cast<string*>(s);
|
||||||
};
|
};
|
||||||
evbuffer_add_reference(out_buffer.get(), serialized->data(), serialized->size(), cleanup, serialized);
|
evbuffer_add_reference(out_buffer.get(), serialized->data(), serialized->size(), cleanup, serialized);
|
||||||
this->send_response(req, 200, "application/json", out_buffer.get());
|
this->send_response(req, 200, "application/json", out_buffer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPServer::thread_fn() {
|
||||||
|
event_base_loop(this->base.get(), EVLOOP_NO_EXIT_ON_EMPTY);
|
||||||
|
}
|
||||||
|
|||||||
+13
-6
@@ -25,6 +25,9 @@ public:
|
|||||||
void listen(int port);
|
void listen(int port);
|
||||||
void add_socket(int fd);
|
void add_socket(int fd);
|
||||||
|
|
||||||
|
void schedule_stop();
|
||||||
|
void wait_for_stop();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class http_error : public std::runtime_error {
|
class http_error : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
@@ -33,7 +36,11 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<ServerState> state;
|
std::shared_ptr<ServerState> state;
|
||||||
|
std::shared_ptr<struct event_base> base;
|
||||||
std::shared_ptr<struct evhttp> http;
|
std::shared_ptr<struct evhttp> http;
|
||||||
|
std::thread th;
|
||||||
|
|
||||||
|
void thread_fn();
|
||||||
|
|
||||||
static void dispatch_handle_request(struct evhttp_request* req, void* ctx);
|
static void dispatch_handle_request(struct evhttp_request* req, void* ctx);
|
||||||
void handle_request(struct evhttp_request* req);
|
void handle_request(struct evhttp_request* req);
|
||||||
@@ -49,12 +56,12 @@ protected:
|
|||||||
const std::string& key,
|
const std::string& key,
|
||||||
const std::string* _default = nullptr);
|
const std::string* _default = nullptr);
|
||||||
|
|
||||||
JSON generate_quest_json(std::shared_ptr<const Quest> q) const;
|
static JSON generate_quest_json_st(std::shared_ptr<const Quest> q);
|
||||||
JSON generate_client_config_json(const Client::Config& config) const;
|
static JSON generate_client_config_json_st(const Client::Config& config);
|
||||||
JSON generate_license_json(std::shared_ptr<const License> l) const;
|
static JSON generate_license_json_st(std::shared_ptr<const License> l);
|
||||||
JSON generate_game_client_json(std::shared_ptr<const Client> c) const;
|
static JSON generate_game_client_json_st(std::shared_ptr<const Client> c, std::shared_ptr<const ItemNameIndex> item_name_index);
|
||||||
JSON generate_proxy_client_json(std::shared_ptr<const ProxyServer::LinkedSession> ses) const;
|
static JSON generate_proxy_client_json_st(std::shared_ptr<const ProxyServer::LinkedSession> ses);
|
||||||
JSON generate_lobby_json(std::shared_ptr<const Lobby> l) const;
|
static JSON generate_lobby_json_st(std::shared_ptr<const Lobby> l, std::shared_ptr<const ItemNameIndex> item_name_index);
|
||||||
JSON generate_game_server_clients_json() const;
|
JSON generate_game_server_clients_json() const;
|
||||||
JSON generate_proxy_server_clients_json() const;
|
JSON generate_proxy_server_clients_json() const;
|
||||||
JSON generate_server_info_json() const;
|
JSON generate_server_info_json() const;
|
||||||
|
|||||||
@@ -2518,6 +2518,9 @@ Action a_run_server_replay_log(
|
|||||||
if (state->bb_patch_server) {
|
if (state->bb_patch_server) {
|
||||||
state->bb_patch_server->schedule_stop();
|
state->bb_patch_server->schedule_stop();
|
||||||
}
|
}
|
||||||
|
if (http_server) {
|
||||||
|
http_server->schedule_stop();
|
||||||
|
}
|
||||||
if (state->pc_patch_server) {
|
if (state->pc_patch_server) {
|
||||||
config_log.info("Waiting for PC_V2 patch server to stop");
|
config_log.info("Waiting for PC_V2 patch server to stop");
|
||||||
state->pc_patch_server->wait_for_stop();
|
state->pc_patch_server->wait_for_stop();
|
||||||
@@ -2526,6 +2529,10 @@ Action a_run_server_replay_log(
|
|||||||
config_log.info("Waiting for BB_V4 patch server to stop");
|
config_log.info("Waiting for BB_V4 patch server to stop");
|
||||||
state->bb_patch_server->wait_for_stop();
|
state->bb_patch_server->wait_for_stop();
|
||||||
}
|
}
|
||||||
|
if (http_server) {
|
||||||
|
config_log.info("Waiting for HTTP server to stop");
|
||||||
|
http_server->wait_for_stop();
|
||||||
|
}
|
||||||
state->proxy_server.reset(); // Break reference cycle
|
state->proxy_server.reset(); // Break reference cycle
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+93
-89
@@ -393,8 +393,12 @@ shared_ptr<const ItemData::StackLimits> ServerState::item_stack_limits(Version v
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<const ItemNameIndex> ServerState::item_name_index_opt(Version version) const {
|
||||||
|
return this->item_name_indexes.at(static_cast<size_t>(version));
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) const {
|
shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) const {
|
||||||
auto ret = this->item_name_indexes.at(static_cast<size_t>(version));
|
auto ret = this->item_name_index_opt(version);
|
||||||
if (ret == nullptr) {
|
if (ret == nullptr) {
|
||||||
throw runtime_error("no item name index exists for this version");
|
throw runtime_error("no item name index exists for this version");
|
||||||
}
|
}
|
||||||
@@ -559,11 +563,11 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_log.info("Loading configuration");
|
config_log.info("Loading configuration");
|
||||||
this->config_json = JSON::parse(load_file(this->config_filename));
|
this->config_json = make_shared<JSON>(JSON::parse(load_file(this->config_filename)));
|
||||||
|
|
||||||
auto parse_behavior_switch = [&](const string& json_key, BehaviorSwitch default_value) -> ServerState::BehaviorSwitch {
|
auto parse_behavior_switch = [&](const string& json_key, BehaviorSwitch default_value) -> ServerState::BehaviorSwitch {
|
||||||
try {
|
try {
|
||||||
string behavior = this->config_json.get_string(json_key);
|
string behavior = this->config_json->get_string(json_key);
|
||||||
if (behavior == "Off") {
|
if (behavior == "Off") {
|
||||||
return ServerState::BehaviorSwitch::OFF;
|
return ServerState::BehaviorSwitch::OFF;
|
||||||
} else if (behavior == "OffByDefault") {
|
} else if (behavior == "OffByDefault") {
|
||||||
@@ -580,11 +584,11 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this->name = this->config_json.at("ServerName").as_string();
|
this->name = this->config_json->at("ServerName").as_string();
|
||||||
|
|
||||||
if (!this->one_time_config_loaded) {
|
if (!this->one_time_config_loaded) {
|
||||||
try {
|
try {
|
||||||
this->username = this->config_json.at("User").as_string();
|
this->username = this->config_json->at("User").as_string();
|
||||||
if (this->username == "$SUDO_USER") {
|
if (this->username == "$SUDO_USER") {
|
||||||
const char* user_from_env = getenv("SUDO_USER");
|
const char* user_from_env = getenv("SUDO_USER");
|
||||||
if (!user_from_env) {
|
if (!user_from_env) {
|
||||||
@@ -595,15 +599,15 @@ void ServerState::load_config_early() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->set_port_configuration(parse_port_configuration(this->config_json.at("PortConfiguration")));
|
this->set_port_configuration(parse_port_configuration(this->config_json->at("PortConfiguration")));
|
||||||
try {
|
try {
|
||||||
auto spec = this->parse_port_spec(this->config_json.at("DNSServerPort"));
|
auto spec = this->parse_port_spec(this->config_json->at("DNSServerPort"));
|
||||||
this->dns_server_addr = std::move(spec.first);
|
this->dns_server_addr = std::move(spec.first);
|
||||||
this->dns_server_port = spec.second;
|
this->dns_server_port = spec.second;
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& item : this->config_json.at("IPStackListen").as_list()) {
|
for (const auto& item : this->config_json->at("IPStackListen").as_list()) {
|
||||||
if (item->is_int()) {
|
if (item->is_int()) {
|
||||||
this->ip_stack_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
this->ip_stack_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
||||||
} else {
|
} else {
|
||||||
@@ -613,7 +617,7 @@ void ServerState::load_config_early() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& item : this->config_json.at("PPPStackListen").as_list()) {
|
for (const auto& item : this->config_json->at("PPPStackListen").as_list()) {
|
||||||
if (item->is_int()) {
|
if (item->is_int()) {
|
||||||
this->ppp_stack_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
this->ppp_stack_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
||||||
} else {
|
} else {
|
||||||
@@ -623,7 +627,7 @@ void ServerState::load_config_early() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& item : this->config_json.at("PPPRawListen").as_list()) {
|
for (const auto& item : this->config_json->at("PPPRawListen").as_list()) {
|
||||||
if (item->is_int()) {
|
if (item->is_int()) {
|
||||||
this->ppp_raw_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
this->ppp_raw_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
||||||
} else {
|
} else {
|
||||||
@@ -633,7 +637,7 @@ void ServerState::load_config_early() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& item : this->config_json.at("HTTPListen").as_list()) {
|
for (const auto& item : this->config_json->at("HTTPListen").as_list()) {
|
||||||
if (item->is_int()) {
|
if (item->is_int()) {
|
||||||
this->http_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
this->http_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
|
||||||
} else {
|
} else {
|
||||||
@@ -646,7 +650,7 @@ void ServerState::load_config_early() {
|
|||||||
this->one_time_config_loaded = true;
|
this->one_time_config_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto local_address_str = this->config_json.at("LocalAddress").as_string();
|
auto local_address_str = this->config_json->at("LocalAddress").as_string();
|
||||||
try {
|
try {
|
||||||
this->local_address = this->all_addresses.at(local_address_str);
|
this->local_address = this->all_addresses.at(local_address_str);
|
||||||
string addr_str = string_for_address(this->local_address);
|
string addr_str = string_for_address(this->local_address);
|
||||||
@@ -659,7 +663,7 @@ void ServerState::load_config_early() {
|
|||||||
this->all_addresses.erase("<local>");
|
this->all_addresses.erase("<local>");
|
||||||
this->all_addresses.emplace("<local>", this->local_address);
|
this->all_addresses.emplace("<local>", this->local_address);
|
||||||
|
|
||||||
auto external_address_str = this->config_json.at("ExternalAddress").as_string();
|
auto external_address_str = this->config_json->at("ExternalAddress").as_string();
|
||||||
try {
|
try {
|
||||||
this->external_address = this->all_addresses.at(external_address_str);
|
this->external_address = this->all_addresses.at(external_address_str);
|
||||||
string addr_str = string_for_address(this->external_address);
|
string addr_str = string_for_address(this->external_address);
|
||||||
@@ -672,32 +676,32 @@ void ServerState::load_config_early() {
|
|||||||
this->all_addresses.erase("<external>");
|
this->all_addresses.erase("<external>");
|
||||||
this->all_addresses.emplace("<external>", this->external_address);
|
this->all_addresses.emplace("<external>", this->external_address);
|
||||||
|
|
||||||
this->client_ping_interval_usecs = this->config_json.get_int("ClientPingInterval", 30000000);
|
this->client_ping_interval_usecs = this->config_json->get_int("ClientPingInterval", 30000000);
|
||||||
this->client_idle_timeout_usecs = this->config_json.get_int("ClientIdleTimeout", 60000000);
|
this->client_idle_timeout_usecs = this->config_json->get_int("ClientIdleTimeout", 60000000);
|
||||||
this->patch_client_idle_timeout_usecs = this->config_json.get_int("PatchClientIdleTimeout", 300000000);
|
this->patch_client_idle_timeout_usecs = this->config_json->get_int("PatchClientIdleTimeout", 300000000);
|
||||||
|
|
||||||
this->ip_stack_debug = this->config_json.get_bool("IPStackDebug", false);
|
this->ip_stack_debug = this->config_json->get_bool("IPStackDebug", false);
|
||||||
this->allow_unregistered_users = this->config_json.get_bool("AllowUnregisteredUsers", false);
|
this->allow_unregistered_users = this->config_json->get_bool("AllowUnregisteredUsers", false);
|
||||||
this->allow_pc_nte = this->config_json.get_bool("AllowPCNTE", false);
|
this->allow_pc_nte = this->config_json->get_bool("AllowPCNTE", false);
|
||||||
this->use_temp_licenses_for_prototypes = this->config_json.get_bool("UseTemporaryLicensesForPrototypes", true);
|
this->use_temp_licenses_for_prototypes = this->config_json->get_bool("UseTemporaryLicensesForPrototypes", true);
|
||||||
this->allowed_drop_modes_v1_v2_normal = this->config_json.get_int("AllowedDropModesV1V2Normal", 0x1F);
|
this->allowed_drop_modes_v1_v2_normal = this->config_json->get_int("AllowedDropModesV1V2Normal", 0x1F);
|
||||||
this->allowed_drop_modes_v1_v2_battle = this->config_json.get_int("AllowedDropModesV1V2Battle", 0x07);
|
this->allowed_drop_modes_v1_v2_battle = this->config_json->get_int("AllowedDropModesV1V2Battle", 0x07);
|
||||||
this->allowed_drop_modes_v1_v2_challenge = this->config_json.get_int("AllowedDropModesV1V2Challenge", 0x07);
|
this->allowed_drop_modes_v1_v2_challenge = this->config_json->get_int("AllowedDropModesV1V2Challenge", 0x07);
|
||||||
this->allowed_drop_modes_v3_normal = this->config_json.get_int("AllowedDropModesV3Normal", 0x1F);
|
this->allowed_drop_modes_v3_normal = this->config_json->get_int("AllowedDropModesV3Normal", 0x1F);
|
||||||
this->allowed_drop_modes_v3_battle = this->config_json.get_int("AllowedDropModesV3Battle", 0x07);
|
this->allowed_drop_modes_v3_battle = this->config_json->get_int("AllowedDropModesV3Battle", 0x07);
|
||||||
this->allowed_drop_modes_v3_challenge = this->config_json.get_int("AllowedDropModesV3Challenge", 0x07);
|
this->allowed_drop_modes_v3_challenge = this->config_json->get_int("AllowedDropModesV3Challenge", 0x07);
|
||||||
this->allowed_drop_modes_v4_normal = this->config_json.get_int("AllowedDropModesV4Normal", 0x1D);
|
this->allowed_drop_modes_v4_normal = this->config_json->get_int("AllowedDropModesV4Normal", 0x1D);
|
||||||
this->allowed_drop_modes_v4_battle = this->config_json.get_int("AllowedDropModesV4Battle", 0x05);
|
this->allowed_drop_modes_v4_battle = this->config_json->get_int("AllowedDropModesV4Battle", 0x05);
|
||||||
this->allowed_drop_modes_v4_challenge = this->config_json.get_int("AllowedDropModesV4Challenge", 0x05);
|
this->allowed_drop_modes_v4_challenge = this->config_json->get_int("AllowedDropModesV4Challenge", 0x05);
|
||||||
this->default_drop_mode_v1_v2_normal = this->config_json.get_enum("DefaultDropModeV1V2Normal", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v1_v2_normal = this->config_json->get_enum("DefaultDropModeV1V2Normal", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v1_v2_battle = this->config_json.get_enum("DefaultDropModeV1V2Battle", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v1_v2_battle = this->config_json->get_enum("DefaultDropModeV1V2Battle", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v1_v2_challenge = this->config_json.get_enum("DefaultDropModeV1V2Challenge", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v1_v2_challenge = this->config_json->get_enum("DefaultDropModeV1V2Challenge", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v3_normal = this->config_json.get_enum("DefaultDropModeV3Normal", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v3_normal = this->config_json->get_enum("DefaultDropModeV3Normal", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v3_battle = this->config_json.get_enum("DefaultDropModeV3Battle", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v3_battle = this->config_json->get_enum("DefaultDropModeV3Battle", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v3_challenge = this->config_json.get_enum("DefaultDropModeV3Challenge", Lobby::DropMode::CLIENT);
|
this->default_drop_mode_v3_challenge = this->config_json->get_enum("DefaultDropModeV3Challenge", Lobby::DropMode::CLIENT);
|
||||||
this->default_drop_mode_v4_normal = this->config_json.get_enum("DefaultDropModeV4Normal", Lobby::DropMode::SERVER_SHARED);
|
this->default_drop_mode_v4_normal = this->config_json->get_enum("DefaultDropModeV4Normal", Lobby::DropMode::SERVER_SHARED);
|
||||||
this->default_drop_mode_v4_battle = this->config_json.get_enum("DefaultDropModeV4Battle", Lobby::DropMode::SERVER_SHARED);
|
this->default_drop_mode_v4_battle = this->config_json->get_enum("DefaultDropModeV4Battle", Lobby::DropMode::SERVER_SHARED);
|
||||||
this->default_drop_mode_v4_challenge = this->config_json.get_enum("DefaultDropModeV4Challenge", Lobby::DropMode::SERVER_SHARED);
|
this->default_drop_mode_v4_challenge = this->config_json->get_enum("DefaultDropModeV4Challenge", Lobby::DropMode::SERVER_SHARED);
|
||||||
if ((this->default_drop_mode_v4_normal == Lobby::DropMode::CLIENT) ||
|
if ((this->default_drop_mode_v4_normal == Lobby::DropMode::CLIENT) ||
|
||||||
(this->default_drop_mode_v4_battle == Lobby::DropMode::CLIENT) ||
|
(this->default_drop_mode_v4_battle == Lobby::DropMode::CLIENT) ||
|
||||||
(this->default_drop_mode_v4_challenge == Lobby::DropMode::CLIENT)) {
|
(this->default_drop_mode_v4_challenge == Lobby::DropMode::CLIENT)) {
|
||||||
@@ -710,20 +714,20 @@ void ServerState::load_config_early() {
|
|||||||
|
|
||||||
this->quest_flag_persist_mask.update_all(true);
|
this->quest_flag_persist_mask.update_all(true);
|
||||||
try {
|
try {
|
||||||
for (const auto& flag_id_json : this->config_json.get_list("PreventPersistQuestFlags")) {
|
for (const auto& flag_id_json : this->config_json->get_list("PreventPersistQuestFlags")) {
|
||||||
this->quest_flag_persist_mask.clear(flag_id_json->as_int());
|
this->quest_flag_persist_mask.clear(flag_id_json->as_int());
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->persistent_game_idle_timeout_usecs = this->config_json.get_int("PersistentGameIdleTimeout", 0);
|
this->persistent_game_idle_timeout_usecs = this->config_json->get_int("PersistentGameIdleTimeout", 0);
|
||||||
this->cheat_mode_behavior = parse_behavior_switch("CheatModeBehavior", BehaviorSwitch::OFF_BY_DEFAULT);
|
this->cheat_mode_behavior = parse_behavior_switch("CheatModeBehavior", BehaviorSwitch::OFF_BY_DEFAULT);
|
||||||
this->default_rare_notifs_enabled_v1_v2 = this->config_json.get_bool("RareNotificationsEnabledByDefault", false);
|
this->default_rare_notifs_enabled_v1_v2 = this->config_json->get_bool("RareNotificationsEnabledByDefault", false);
|
||||||
this->default_rare_notifs_enabled_v3_v4 = this->default_rare_notifs_enabled_v1_v2;
|
this->default_rare_notifs_enabled_v3_v4 = this->default_rare_notifs_enabled_v1_v2;
|
||||||
this->default_rare_notifs_enabled_v1_v2 = this->config_json.get_bool("RareNotificationsEnabledByDefaultV1V2", this->default_rare_notifs_enabled_v1_v2);
|
this->default_rare_notifs_enabled_v1_v2 = this->config_json->get_bool("RareNotificationsEnabledByDefaultV1V2", this->default_rare_notifs_enabled_v1_v2);
|
||||||
this->default_rare_notifs_enabled_v3_v4 = this->config_json.get_bool("RareNotificationsEnabledByDefaultV3V4", this->default_rare_notifs_enabled_v3_v4);
|
this->default_rare_notifs_enabled_v3_v4 = this->config_json->get_bool("RareNotificationsEnabledByDefaultV3V4", this->default_rare_notifs_enabled_v3_v4);
|
||||||
this->ep3_send_function_call_enabled = this->config_json.get_bool("EnableEpisode3SendFunctionCall", false);
|
this->ep3_send_function_call_enabled = this->config_json->get_bool("EnableEpisode3SendFunctionCall", false);
|
||||||
this->catch_handler_exceptions = this->config_json.get_bool("CatchHandlerExceptions", true);
|
this->catch_handler_exceptions = this->config_json->get_bool("CatchHandlerExceptions", true);
|
||||||
|
|
||||||
auto parse_int_list = +[](const JSON& json) -> vector<uint32_t> {
|
auto parse_int_list = +[](const JSON& json) -> vector<uint32_t> {
|
||||||
vector<uint32_t> ret;
|
vector<uint32_t> ret;
|
||||||
@@ -733,27 +737,27 @@ void ServerState::load_config_early() {
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
this->ep3_infinite_meseta = this->config_json.get_bool("Episode3InfiniteMeseta", false);
|
this->ep3_infinite_meseta = this->config_json->get_bool("Episode3InfiniteMeseta", false);
|
||||||
try {
|
try {
|
||||||
this->ep3_defeat_player_meseta_rewards = parse_int_list(this->config_json.at("Episode3DefeatPlayerMeseta"));
|
this->ep3_defeat_player_meseta_rewards = parse_int_list(this->config_json->at("Episode3DefeatPlayerMeseta"));
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->ep3_defeat_player_meseta_rewards = {300, 400, 500, 600, 700};
|
this->ep3_defeat_player_meseta_rewards = {300, 400, 500, 600, 700};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this->ep3_defeat_com_meseta_rewards = parse_int_list(this->config_json.get("Episode3DefeatCOMMeseta", JSON::list()));
|
this->ep3_defeat_com_meseta_rewards = parse_int_list(this->config_json->get("Episode3DefeatCOMMeseta", JSON::list()));
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->ep3_defeat_com_meseta_rewards = {100, 200, 300, 400, 500};
|
this->ep3_defeat_com_meseta_rewards = {100, 200, 300, 400, 500};
|
||||||
}
|
}
|
||||||
this->ep3_final_round_meseta_bonus = this->config_json.get_int("Episode3FinalRoundMesetaBonus", 300);
|
this->ep3_final_round_meseta_bonus = this->config_json->get_int("Episode3FinalRoundMesetaBonus", 300);
|
||||||
this->ep3_jukebox_is_free = this->config_json.get_bool("Episode3JukeboxIsFree", false);
|
this->ep3_jukebox_is_free = this->config_json->get_bool("Episode3JukeboxIsFree", false);
|
||||||
this->ep3_behavior_flags = this->config_json.get_int("Episode3BehaviorFlags", false);
|
this->ep3_behavior_flags = this->config_json->get_int("Episode3BehaviorFlags", false);
|
||||||
this->ep3_card_auction_points = this->config_json.get_int("CardAuctionPoints", 0);
|
this->ep3_card_auction_points = this->config_json->get_int("CardAuctionPoints", 0);
|
||||||
this->hide_download_commands = this->config_json.get_bool("HideDownloadCommands", true);
|
this->hide_download_commands = this->config_json->get_bool("HideDownloadCommands", true);
|
||||||
this->proxy_allow_save_files = this->config_json.get_bool("ProxyAllowSaveFiles", true);
|
this->proxy_allow_save_files = this->config_json->get_bool("ProxyAllowSaveFiles", true);
|
||||||
this->proxy_enable_login_options = this->config_json.get_bool("ProxyEnableLoginOptions", false);
|
this->proxy_enable_login_options = this->config_json->get_bool("ProxyEnableLoginOptions", false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto& i = this->config_json.at("CardAuctionSize");
|
const auto& i = this->config_json->at("CardAuctionSize");
|
||||||
if (i.is_int()) {
|
if (i.is_int()) {
|
||||||
this->ep3_card_auction_min_size = i.as_int();
|
this->ep3_card_auction_min_size = i.as_int();
|
||||||
this->ep3_card_auction_max_size = this->ep3_card_auction_min_size;
|
this->ep3_card_auction_max_size = this->ep3_card_auction_min_size;
|
||||||
@@ -768,7 +772,7 @@ void ServerState::load_config_early() {
|
|||||||
|
|
||||||
if (!this->is_replay) {
|
if (!this->is_replay) {
|
||||||
this->ep3_lobby_banners.clear();
|
this->ep3_lobby_banners.clear();
|
||||||
for (const auto& it : this->config_json.get("Episode3LobbyBanners", JSON::list()).as_list()) {
|
for (const auto& it : this->config_json->get("Episode3LobbyBanners", JSON::list()).as_list()) {
|
||||||
string path = "system/ep3/banners/" + it->at(2).as_string();
|
string path = "system/ep3/banners/" + it->at(2).as_string();
|
||||||
|
|
||||||
string compressed_gvm_data;
|
string compressed_gvm_data;
|
||||||
@@ -820,7 +824,7 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
const auto& categories_json = this->config_json.at("Episode3EXResultValues");
|
const auto& categories_json = this->config_json->at("Episode3EXResultValues");
|
||||||
this->ep3_default_ex_values = parse_ep3_ex_result_cmd(categories_json.at("Default"));
|
this->ep3_default_ex_values = parse_ep3_ex_result_cmd(categories_json.at("Default"));
|
||||||
try {
|
try {
|
||||||
this->ep3_tournament_ex_values = parse_ep3_ex_result_cmd(categories_json.at("Tournament"));
|
this->ep3_tournament_ex_values = parse_ep3_ex_result_cmd(categories_json.at("Tournament"));
|
||||||
@@ -835,7 +839,7 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto& stack_limits_tables_json = this->config_json.at("ItemStackLimits");
|
const auto& stack_limits_tables_json = this->config_json->at("ItemStackLimits");
|
||||||
for (size_t v_s = NUM_PATCH_VERSIONS; v_s < NUM_VERSIONS; v_s++) {
|
for (size_t v_s = NUM_PATCH_VERSIONS; v_s < NUM_VERSIONS; v_s++) {
|
||||||
try {
|
try {
|
||||||
Version v = static_cast<Version>(v_s);
|
Version v = static_cast<Version>(v_s);
|
||||||
@@ -863,25 +867,25 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->bb_global_exp_multiplier = this->config_json.get_int("BBGlobalEXPMultiplier", 1);
|
this->bb_global_exp_multiplier = this->config_json->get_int("BBGlobalEXPMultiplier", 1);
|
||||||
|
|
||||||
set_log_levels_from_json(this->config_json.get("LogLevels", JSON::dict()));
|
set_log_levels_from_json(this->config_json->get("LogLevels", JSON::dict()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this->run_shell_behavior = this->config_json.at("RunInteractiveShell").as_bool()
|
this->run_shell_behavior = this->config_json->at("RunInteractiveShell").as_bool()
|
||||||
? ServerState::RunShellBehavior::ALWAYS
|
? ServerState::RunShellBehavior::ALWAYS
|
||||||
: ServerState::RunShellBehavior::NEVER;
|
: ServerState::RunShellBehavior::NEVER;
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->allow_dc_pc_games = this->config_json.get_bool("AllowDCPCGames", true);
|
this->allow_dc_pc_games = this->config_json->get_bool("AllowDCPCGames", true);
|
||||||
this->allow_gc_xb_games = this->config_json.get_bool("AllowGCXBGames", true);
|
this->allow_gc_xb_games = this->config_json->get_bool("AllowGCXBGames", true);
|
||||||
|
|
||||||
for (auto& order : this->public_lobby_search_orders) {
|
for (auto& order : this->public_lobby_search_orders) {
|
||||||
order.clear();
|
order.clear();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const auto& orders_json = this->config_json.get_list("LobbySearchOrders");
|
const auto& orders_json = this->config_json->get_list("LobbySearchOrders");
|
||||||
for (size_t v_s = 0; v_s < orders_json.size(); v_s++) {
|
for (size_t v_s = 0; v_s < orders_json.size(); v_s++) {
|
||||||
auto& order = this->public_lobby_search_orders.at(v_s);
|
auto& order = this->public_lobby_search_orders.at(v_s);
|
||||||
const auto& order_json = orders_json.at(v_s);
|
const auto& order_json = orders_json.at(v_s);
|
||||||
@@ -899,7 +903,7 @@ void ServerState::load_config_early() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const auto& events_json = this->config_json.get_list("LobbyEvents");
|
const auto& events_json = this->config_json->get_list("LobbyEvents");
|
||||||
for (size_t z = 0; z < events_json.size(); z++) {
|
for (size_t z = 0; z < events_json.size(); z++) {
|
||||||
const auto& v = events_json.at(z);
|
const auto& v = events_json.at(z);
|
||||||
uint8_t event = v->is_int() ? v->as_int() : event_for_name(v->as_string());
|
uint8_t event = v->is_int() ? v->as_int() : event_for_name(v->as_string());
|
||||||
@@ -914,15 +918,15 @@ void ServerState::load_config_early() {
|
|||||||
|
|
||||||
this->pre_lobby_event = 0;
|
this->pre_lobby_event = 0;
|
||||||
try {
|
try {
|
||||||
auto v = this->config_json.at("MenuEvent");
|
auto v = this->config_json->at("MenuEvent");
|
||||||
this->pre_lobby_event = v.is_int() ? v.as_int() : event_for_name(v.as_string());
|
this->pre_lobby_event = v.is_int() ? v.as_int() : event_for_name(v.as_string());
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->ep3_menu_song = this->config_json.get_int("Episode3MenuSong", -1);
|
this->ep3_menu_song = this->config_json->get_int("Episode3MenuSong", -1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this->quest_category_index = make_shared<QuestCategoryIndex>(this->config_json.at("QuestCategories"));
|
this->quest_category_index = make_shared<QuestCategoryIndex>(this->config_json->at("QuestCategories"));
|
||||||
} catch (const exception& e) {
|
} catch (const exception& e) {
|
||||||
throw runtime_error(string_printf(
|
throw runtime_error(string_printf(
|
||||||
"QuestCategories is missing or invalid in config.json (%s) - see config.example.json for an example", e.what()));
|
"QuestCategories is missing or invalid in config.json (%s) - see config.example.json for an example", e.what()));
|
||||||
@@ -941,9 +945,9 @@ void ServerState::load_config_early() {
|
|||||||
"Return to the\nmain menu", MenuItem::Flag::INVISIBLE_IN_INFO_MENU);
|
"Return to the\nmain menu", MenuItem::Flag::INVISIBLE_IN_INFO_MENU);
|
||||||
{
|
{
|
||||||
auto blank_json = JSON::list();
|
auto blank_json = JSON::list();
|
||||||
const JSON& default_json = this->config_json.get("InformationMenuContents", blank_json);
|
const JSON& default_json = this->config_json->get("InformationMenuContents", blank_json);
|
||||||
const JSON& v2_json = this->config_json.get("InformationMenuContentsV1V2", default_json);
|
const JSON& v2_json = this->config_json->get("InformationMenuContentsV1V2", default_json);
|
||||||
const JSON& v3_json = this->config_json.get("InformationMenuContentsV3", default_json);
|
const JSON& v3_json = this->config_json->get("InformationMenuContentsV3", default_json);
|
||||||
|
|
||||||
uint32_t item_id = 0;
|
uint32_t item_id = 0;
|
||||||
for (const auto& item : v2_json.as_list()) {
|
for (const auto& item : v2_json.as_list()) {
|
||||||
@@ -974,7 +978,7 @@ void ServerState::load_config_early() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
map<string, const JSON&> sorted_jsons;
|
map<string, const JSON&> sorted_jsons;
|
||||||
for (const auto& it : this->config_json.at(key).as_dict()) {
|
for (const auto& it : this->config_json->at(key).as_dict()) {
|
||||||
sorted_jsons.emplace(it.first, *it.second);
|
sorted_jsons.emplace(it.first, *it.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,7 +1004,7 @@ void ServerState::load_config_early() {
|
|||||||
this->proxy_destinations_menu_xb = generate_proxy_destinations_menu(this->proxy_destinations_xb, "ProxyDestinations-XB");
|
this->proxy_destinations_menu_xb = generate_proxy_destinations_menu(this->proxy_destinations_xb, "ProxyDestinations-XB");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const string& netloc_str = this->config_json.get_string("ProxyDestination-Patch");
|
const string& netloc_str = this->config_json->get_string("ProxyDestination-Patch");
|
||||||
this->proxy_destination_patch = parse_netloc(netloc_str);
|
this->proxy_destination_patch = parse_netloc(netloc_str);
|
||||||
config_log.info("Patch server proxy is enabled with destination %s", netloc_str.c_str());
|
config_log.info("Patch server proxy is enabled with destination %s", netloc_str.c_str());
|
||||||
for (auto& it : this->name_to_port_config) {
|
for (auto& it : this->name_to_port_config) {
|
||||||
@@ -1013,7 +1017,7 @@ void ServerState::load_config_early() {
|
|||||||
this->proxy_destination_patch.second = 0;
|
this->proxy_destination_patch.second = 0;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const string& netloc_str = this->config_json.get_string("ProxyDestination-BB");
|
const string& netloc_str = this->config_json->get_string("ProxyDestination-BB");
|
||||||
this->proxy_destination_bb = parse_netloc(netloc_str);
|
this->proxy_destination_bb = parse_netloc(netloc_str);
|
||||||
config_log.info("BB proxy is enabled with destination %s", netloc_str.c_str());
|
config_log.info("BB proxy is enabled with destination %s", netloc_str.c_str());
|
||||||
for (auto& it : this->name_to_port_config) {
|
for (auto& it : this->name_to_port_config) {
|
||||||
@@ -1026,13 +1030,13 @@ void ServerState::load_config_early() {
|
|||||||
this->proxy_destination_bb.second = 0;
|
this->proxy_destination_bb.second = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->welcome_message = this->config_json.get_string("WelcomeMessage", "");
|
this->welcome_message = this->config_json->get_string("WelcomeMessage", "");
|
||||||
this->pc_patch_server_message = this->config_json.get_string("PCPatchServerMessage", "");
|
this->pc_patch_server_message = this->config_json->get_string("PCPatchServerMessage", "");
|
||||||
this->bb_patch_server_message = this->config_json.get_string("BBPatchServerMessage", "");
|
this->bb_patch_server_message = this->config_json->get_string("BBPatchServerMessage", "");
|
||||||
|
|
||||||
this->team_reward_defs_json = nullptr;
|
this->team_reward_defs_json = nullptr;
|
||||||
try {
|
try {
|
||||||
this->team_reward_defs_json = std::move(this->config_json.at("TeamRewards"));
|
this->team_reward_defs_json = std::move(this->config_json->at("TeamRewards"));
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,14 +1045,14 @@ void ServerState::load_config_early() {
|
|||||||
try {
|
try {
|
||||||
string key = "RareEnemyRates-";
|
string key = "RareEnemyRates-";
|
||||||
key += token_name_for_difficulty(z);
|
key += token_name_for_difficulty(z);
|
||||||
this->rare_enemy_rates_by_difficulty[z] = make_shared<Map::RareEnemyRates>(this->config_json.at(key));
|
this->rare_enemy_rates_by_difficulty[z] = make_shared<Map::RareEnemyRates>(this->config_json->at(key));
|
||||||
prev = this->rare_enemy_rates_by_difficulty[z];
|
prev = this->rare_enemy_rates_by_difficulty[z];
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->rare_enemy_rates_by_difficulty[z] = prev;
|
this->rare_enemy_rates_by_difficulty[z] = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this->rare_enemy_rates_challenge = make_shared<Map::RareEnemyRates>(this->config_json.at("RareEnemyRates-Challenge"));
|
this->rare_enemy_rates_challenge = make_shared<Map::RareEnemyRates>(this->config_json->at("RareEnemyRates-Challenge"));
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->rare_enemy_rates_challenge = Map::DEFAULT_RARE_ENEMIES;
|
this->rare_enemy_rates_challenge = Map::DEFAULT_RARE_ENEMIES;
|
||||||
}
|
}
|
||||||
@@ -1057,7 +1061,7 @@ void ServerState::load_config_early() {
|
|||||||
this->min_levels_v4[1] = DEFAULT_MIN_LEVELS_V4_EP2;
|
this->min_levels_v4[1] = DEFAULT_MIN_LEVELS_V4_EP2;
|
||||||
this->min_levels_v4[2] = DEFAULT_MIN_LEVELS_V4_EP4;
|
this->min_levels_v4[2] = DEFAULT_MIN_LEVELS_V4_EP4;
|
||||||
try {
|
try {
|
||||||
for (const auto& ep_it : this->config_json.get_dict("BBMinimumLevels")) {
|
for (const auto& ep_it : this->config_json->get_dict("BBMinimumLevels")) {
|
||||||
array<size_t, 4> levels({0, 0, 0, 0});
|
array<size_t, 4> levels({0, 0, 0, 0});
|
||||||
for (size_t z = 0; z < 4; z++) {
|
for (size_t z = 0; z < 4; z++) {
|
||||||
levels[z] = ep_it.second->get_int(z) - 1;
|
levels[z] = ep_it.second->get_int(z) - 1;
|
||||||
@@ -1083,7 +1087,7 @@ void ServerState::load_config_early() {
|
|||||||
void ServerState::load_config_late() {
|
void ServerState::load_config_late() {
|
||||||
this->ep3_card_auction_pool.clear();
|
this->ep3_card_auction_pool.clear();
|
||||||
try {
|
try {
|
||||||
for (const auto& it : this->config_json.get_dict("CardAuctionPool")) {
|
for (const auto& it : this->config_json->get_dict("CardAuctionPool")) {
|
||||||
uint16_t card_id;
|
uint16_t card_id;
|
||||||
try {
|
try {
|
||||||
card_id = this->ep3_card_index->definition_for_name_normalized(it.first)->def.card_id;
|
card_id = this->ep3_card_index->definition_for_name_normalized(it.first)->def.card_id;
|
||||||
@@ -1104,7 +1108,7 @@ void ServerState::load_config_late() {
|
|||||||
}
|
}
|
||||||
if (this->ep3_card_index) {
|
if (this->ep3_card_index) {
|
||||||
try {
|
try {
|
||||||
const auto& ep3_trap_cards_json = this->config_json.get_list("Episode3TrapCards");
|
const auto& ep3_trap_cards_json = this->config_json->get_list("Episode3TrapCards");
|
||||||
if (!ep3_trap_cards_json.empty()) {
|
if (!ep3_trap_cards_json.empty()) {
|
||||||
if (ep3_trap_cards_json.size() != 5) {
|
if (ep3_trap_cards_json.size() != 5) {
|
||||||
throw runtime_error("Episode3TrapCards must be a list of 5 lists");
|
throw runtime_error("Episode3TrapCards must be a list of 5 lists");
|
||||||
@@ -1137,7 +1141,7 @@ void ServerState::load_config_late() {
|
|||||||
this->secret_lottery_results.clear();
|
this->secret_lottery_results.clear();
|
||||||
if (this->item_name_index(Version::BB_V4)) {
|
if (this->item_name_index(Version::BB_V4)) {
|
||||||
try {
|
try {
|
||||||
for (const auto& type_it : this->config_json.get_list("QuestF95EResultItems")) {
|
for (const auto& type_it : this->config_json->get_list("QuestF95EResultItems")) {
|
||||||
auto& type_res = this->quest_F95E_results.emplace_back();
|
auto& type_res = this->quest_F95E_results.emplace_back();
|
||||||
for (const auto& difficulty_it : type_it->as_list()) {
|
for (const auto& difficulty_it : type_it->as_list()) {
|
||||||
auto& difficulty_res = type_res.emplace_back();
|
auto& difficulty_res = type_res.emplace_back();
|
||||||
@@ -1149,7 +1153,7 @@ void ServerState::load_config_late() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& it : this->config_json.get_list("QuestF95FResultItems")) {
|
for (const auto& it : this->config_json->get_list("QuestF95FResultItems")) {
|
||||||
auto& list = it->as_list();
|
auto& list = it->as_list();
|
||||||
size_t price = list.at(0)->as_int();
|
size_t price = list.at(0)->as_int();
|
||||||
this->quest_F95F_results.emplace_back(make_pair(price, this->parse_item_description(Version::BB_V4, list.at(1)->as_string())));
|
this->quest_F95F_results.emplace_back(make_pair(price, this->parse_item_description(Version::BB_V4, list.at(1)->as_string())));
|
||||||
@@ -1157,14 +1161,14 @@ void ServerState::load_config_late() {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this->quest_F960_failure_results = QuestF960Result(this->config_json.at("QuestF960FailureResultItems"), this->item_name_index(Version::BB_V4));
|
this->quest_F960_failure_results = QuestF960Result(this->config_json->at("QuestF960FailureResultItems"), this->item_name_index(Version::BB_V4));
|
||||||
for (const auto& it : this->config_json.get_list("QuestF960SuccessResultItems")) {
|
for (const auto& it : this->config_json->get_list("QuestF960SuccessResultItems")) {
|
||||||
this->quest_F960_success_results.emplace_back(*it, this->item_name_index(Version::BB_V4));
|
this->quest_F960_success_results.emplace_back(*it, this->item_name_index(Version::BB_V4));
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const auto& it : this->config_json.get_list("SecretLotteryResultItems")) {
|
for (const auto& it : this->config_json->get_list("SecretLotteryResultItems")) {
|
||||||
this->secret_lottery_results.emplace_back(this->parse_item_description(Version::BB_V4, it->as_string()));
|
this->secret_lottery_results.emplace_back(this->parse_item_description(Version::BB_V4, it->as_string()));
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
|
|||||||
+3
-2
@@ -66,7 +66,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
std::shared_ptr<struct event_base> base;
|
std::shared_ptr<struct event_base> base;
|
||||||
|
|
||||||
std::string config_filename;
|
std::string config_filename;
|
||||||
JSON config_json;
|
std::shared_ptr<const JSON> config_json;
|
||||||
bool is_replay = false;
|
bool is_replay = false;
|
||||||
bool one_time_config_loaded = false;
|
bool one_time_config_loaded = false;
|
||||||
bool default_lobbies_created = false;
|
bool default_lobbies_created = false;
|
||||||
@@ -285,7 +285,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
std::shared_ptr<const ItemParameterTable> item_parameter_table(Version version) const;
|
std::shared_ptr<const ItemParameterTable> item_parameter_table(Version version) const;
|
||||||
std::shared_ptr<const ItemParameterTable> item_parameter_table_for_encode(Version version) const;
|
std::shared_ptr<const ItemParameterTable> item_parameter_table_for_encode(Version version) const;
|
||||||
std::shared_ptr<const ItemData::StackLimits> item_stack_limits(Version version) const;
|
std::shared_ptr<const ItemData::StackLimits> item_stack_limits(Version version) const;
|
||||||
std::shared_ptr<const ItemNameIndex> item_name_index(Version version) const;
|
std::shared_ptr<const ItemNameIndex> item_name_index_opt(Version version) const; // Returns null if missing
|
||||||
|
std::shared_ptr<const ItemNameIndex> item_name_index(Version version) const; // Throws if missing
|
||||||
std::string describe_item(Version version, const ItemData& item, bool include_color_codes) const;
|
std::string describe_item(Version version, const ItemData& item, bool include_color_codes) const;
|
||||||
ItemData parse_item_description(Version version, const std::string& description) const;
|
ItemData parse_item_description(Version version, const std::string& description) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user