move shell to separate thread
This commit is contained in:
+4
-3
@@ -27,10 +27,12 @@ link_directories(${LOCAL_LIB_DIR})
|
|||||||
find_path (LIBEVENT_INCLUDE_DIR NAMES event.h)
|
find_path (LIBEVENT_INCLUDE_DIR NAMES event.h)
|
||||||
find_library (LIBEVENT_LIBRARY NAMES event)
|
find_library (LIBEVENT_LIBRARY NAMES event)
|
||||||
find_library (LIBEVENT_CORE NAMES event_core)
|
find_library (LIBEVENT_CORE NAMES event_core)
|
||||||
|
find_library (LIBEVENT_PTHREADS NAMES event_pthreads)
|
||||||
set (LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR})
|
set (LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR})
|
||||||
set (LIBEVENT_LIBRARIES
|
set (LIBEVENT_LIBRARIES
|
||||||
${LIBEVENT_LIBRARY}
|
${LIBEVENT_LIBRARY}
|
||||||
${LIBEVENT_CORE})
|
${LIBEVENT_CORE}
|
||||||
|
${LIBEVENT_PTHREADS})
|
||||||
|
|
||||||
find_package(phosg REQUIRED)
|
find_package(phosg REQUIRED)
|
||||||
find_package(Iconv REQUIRED)
|
find_package(Iconv REQUIRED)
|
||||||
@@ -81,6 +83,7 @@ set(SOURCES
|
|||||||
src/Episode3/RulerServer.cc
|
src/Episode3/RulerServer.cc
|
||||||
src/Episode3/Server.cc
|
src/Episode3/Server.cc
|
||||||
src/Episode3/Tournament.cc
|
src/Episode3/Tournament.cc
|
||||||
|
src/EventUtils.cc
|
||||||
src/FileContentsCache.cc
|
src/FileContentsCache.cc
|
||||||
src/FunctionCompiler.cc
|
src/FunctionCompiler.cc
|
||||||
src/GSLArchive.cc
|
src/GSLArchive.cc
|
||||||
@@ -121,9 +124,7 @@ set(SOURCES
|
|||||||
src/Server.cc
|
src/Server.cc
|
||||||
src/ServerShell.cc
|
src/ServerShell.cc
|
||||||
src/ServerState.cc
|
src/ServerState.cc
|
||||||
src/Shell.cc
|
|
||||||
src/StaticGameData.cc
|
src/StaticGameData.cc
|
||||||
src/StepGraph.cc
|
|
||||||
src/TeamIndex.cc
|
src/TeamIndex.cc
|
||||||
src/Text.cc
|
src/Text.cc
|
||||||
src/TextIndex.cc
|
src/TextIndex.cc
|
||||||
|
|||||||
+65
-14
@@ -31,21 +31,19 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
CatSession::exit_shell::exit_shell() : runtime_error("shell exited") {}
|
||||||
|
|
||||||
CatSession::CatSession(
|
CatSession::CatSession(
|
||||||
shared_ptr<struct event_base> base,
|
shared_ptr<struct event_base> base,
|
||||||
const struct sockaddr_storage& remote,
|
const struct sockaddr_storage& remote,
|
||||||
Version version,
|
Version version,
|
||||||
shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file)
|
shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file)
|
||||||
: Shell(base),
|
: log(string_printf("[CatSession:%s] ", name_for_enum(version)), proxy_server_log.min_level),
|
||||||
log(string_printf("[CatSession:%s] ", name_for_enum(version)), proxy_server_log.min_level),
|
base(base),
|
||||||
channel(
|
read_event(event_new(this->base.get(), 0, EV_READ | EV_PERSIST, CatSession::dispatch_read_stdin, this), event_free),
|
||||||
version,
|
channel(version, 1, CatSession::dispatch_on_channel_input, CatSession::dispatch_on_channel_error, this, "CatSession"),
|
||||||
1,
|
|
||||||
CatSession::dispatch_on_channel_input,
|
|
||||||
CatSession::dispatch_on_channel_error,
|
|
||||||
this,
|
|
||||||
"CatSession"),
|
|
||||||
bb_key_file(bb_key_file) {
|
bb_key_file(bb_key_file) {
|
||||||
|
|
||||||
if (remote.ss_family != AF_INET) {
|
if (remote.ss_family != AF_INET) {
|
||||||
throw runtime_error("remote is not AF_INET");
|
throw runtime_error("remote is not AF_INET");
|
||||||
}
|
}
|
||||||
@@ -64,6 +62,14 @@ CatSession::CatSession(
|
|||||||
reinterpret_cast<const sockaddr*>(&remote), sizeof(struct sockaddr_in)) != 0) {
|
reinterpret_cast<const sockaddr*>(&remote), sizeof(struct sockaddr_in)) != 0) {
|
||||||
throw runtime_error(string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR()));
|
throw runtime_error(string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event_add(this->read_event.get(), nullptr);
|
||||||
|
this->poll.add(0, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CatSession::execute_command(const std::string& command) {
|
||||||
|
string full_cmd = parse_data_string(command, nullptr, ParseDataFlags::ALLOW_FILES);
|
||||||
|
send_command_with_header(this->channel, full_cmd.data(), full_cmd.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatSession::dispatch_on_channel_input(
|
void CatSession::dispatch_on_channel_input(
|
||||||
@@ -129,9 +135,54 @@ void CatSession::on_channel_error(short events) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatSession::print_prompt() {}
|
void CatSession::dispatch_read_stdin(evutil_socket_t, short, void* ctx) {
|
||||||
|
reinterpret_cast<CatSession*>(ctx)->read_stdin();
|
||||||
void CatSession::execute_command(const std::string& command) {
|
}
|
||||||
string full_cmd = parse_data_string(command, nullptr, ParseDataFlags::ALLOW_FILES);
|
|
||||||
send_command_with_header(this->channel, full_cmd.data(), full_cmd.size());
|
void CatSession::read_stdin() {
|
||||||
|
bool any_command_read = false;
|
||||||
|
for (;;) {
|
||||||
|
auto poll_result = this->poll.poll();
|
||||||
|
short fd_events = 0;
|
||||||
|
try {
|
||||||
|
fd_events = poll_result.at(0);
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fd_events & POLLIN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string command(2048, '\0');
|
||||||
|
if (!fgets(command.data(), command.size(), stdin)) {
|
||||||
|
if (!any_command_read) {
|
||||||
|
// ctrl+d probably; we should exit
|
||||||
|
fputc('\n', stderr);
|
||||||
|
event_base_loopexit(this->base.get(), nullptr);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
break; // probably not EOF; just no more commands for now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim the extra data off the string
|
||||||
|
size_t len = strlen(command.c_str());
|
||||||
|
if (len == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (command[len - 1] == '\n') {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
command.resize(len);
|
||||||
|
any_command_read = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
execute_command(command);
|
||||||
|
} catch (const exit_shell&) {
|
||||||
|
event_base_loopexit(this->base.get(), nullptr);
|
||||||
|
return;
|
||||||
|
} catch (const exception& e) {
|
||||||
|
fprintf(stderr, "FAILED: %s\n", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-5
@@ -14,28 +14,41 @@
|
|||||||
#include "PSOEncryption.hh"
|
#include "PSOEncryption.hh"
|
||||||
#include "PSOProtocol.hh"
|
#include "PSOProtocol.hh"
|
||||||
#include "ServerState.hh"
|
#include "ServerState.hh"
|
||||||
#include "Shell.hh"
|
|
||||||
|
|
||||||
class CatSession : public Shell {
|
class CatSession {
|
||||||
public:
|
public:
|
||||||
CatSession(
|
CatSession(
|
||||||
std::shared_ptr<struct event_base> base,
|
std::shared_ptr<struct event_base> base,
|
||||||
const struct sockaddr_storage& remote,
|
const struct sockaddr_storage& remote,
|
||||||
Version version,
|
Version version,
|
||||||
std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file);
|
std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file);
|
||||||
|
CatSession(const CatSession&) = delete;
|
||||||
|
CatSession(CatSession&&) = delete;
|
||||||
|
CatSession& operator=(const CatSession&) = delete;
|
||||||
|
CatSession& operator=(CatSession&&) = delete;
|
||||||
virtual ~CatSession() = default;
|
virtual ~CatSession() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PrefixedLogger log;
|
PrefixedLogger log;
|
||||||
|
std::shared_ptr<struct event_base> base;
|
||||||
|
std::unique_ptr<struct event, void (*)(struct event*)> read_event;
|
||||||
|
Poll poll;
|
||||||
|
|
||||||
Channel channel;
|
Channel channel;
|
||||||
std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file;
|
std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file;
|
||||||
|
|
||||||
virtual void print_prompt();
|
class exit_shell : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
exit_shell();
|
||||||
|
~exit_shell() = default;
|
||||||
|
};
|
||||||
|
|
||||||
virtual void execute_command(const std::string& command);
|
virtual void execute_command(const std::string& command);
|
||||||
|
|
||||||
static void dispatch_on_channel_input(
|
static void dispatch_read_stdin(evutil_socket_t fd, short events, void* ctx);
|
||||||
Channel& ch, uint16_t command, uint32_t flag, std::string& msg);
|
static void dispatch_on_channel_input(Channel& ch, uint16_t command, uint32_t flag, std::string& msg);
|
||||||
static void dispatch_on_channel_error(Channel& ch, short events);
|
static void dispatch_on_channel_error(Channel& ch, short events);
|
||||||
void on_channel_input(uint16_t command, uint32_t flag, std::string& msg);
|
void on_channel_input(uint16_t command, uint32_t flag, std::string& msg);
|
||||||
void on_channel_error(short events);
|
void on_channel_error(short events);
|
||||||
|
void read_stdin();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2004,6 +2004,15 @@ MapDefinitionTrial::MapDefinitionTrial(const MapDefinition& map)
|
|||||||
for (size_t z = 0; z < this->dialogue_sets.size(); z++) {
|
for (size_t z = 0; z < this->dialogue_sets.size(); z++) {
|
||||||
this->dialogue_sets[z] = map.dialogue_sets[z].sub<8>(0);
|
this->dialogue_sets[z] = map.dialogue_sets[z].sub<8>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: It'd be nice to rewrite start_tile_definitions, since it seems NTE
|
||||||
|
// always expects team A to be represented by 3 and 4, and team B to be
|
||||||
|
// represented by 7 and 8.
|
||||||
|
|
||||||
|
// TODO: NTE also expects team A to always be facing up, and B to always be
|
||||||
|
// facing down, so it would be nice to automatically rotate the map to make
|
||||||
|
// that the case. However, we'd also have to fix up the camera zones and
|
||||||
|
// camera specs, and the spec structure is not (yet) fully understood.
|
||||||
}
|
}
|
||||||
|
|
||||||
MapDefinitionTrial::operator MapDefinition() const {
|
MapDefinitionTrial::operator MapDefinition() const {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "EventUtils.hh"
|
||||||
|
|
||||||
|
#include <event2/event.h>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static void dispatch_forward_to_event_thread(evutil_socket_t, short, void* ctx) {
|
||||||
|
auto* fn = reinterpret_cast<std::function<void()>*>(ctx);
|
||||||
|
(*fn)();
|
||||||
|
delete fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::function<void()>&& fn) {
|
||||||
|
struct timeval tv = {0, 0};
|
||||||
|
std::function<void()>* new_fn = new std::function<void()>(std::move(fn));
|
||||||
|
event_base_once(base.get(), -1, EV_TIMEOUT, dispatch_forward_to_event_thread, new_fn, &tv);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <event2/event.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::function<void()>&& fn);
|
||||||
+53
-22
@@ -1,4 +1,5 @@
|
|||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
|
#include <event2/thread.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -1127,7 +1128,8 @@ Action a_disassemble_set_data_table(
|
|||||||
Action a_check_set_data_table(
|
Action a_check_set_data_table(
|
||||||
"check-set-data-tables", nullptr, +[](Arguments&) {
|
"check-set-data-tables", nullptr, +[](Arguments&) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("set_data_tables");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_set_data_tables(false);
|
||||||
static_game_data_log.min_level = LogLevel::DISABLED;
|
static_game_data_log.min_level = LogLevel::DISABLED;
|
||||||
|
|
||||||
auto get_file_data = [&](Version version, const string& filename) -> shared_ptr<const string> {
|
auto get_file_data = [&](Version version, const string& filename) -> shared_ptr<const string> {
|
||||||
@@ -1330,7 +1332,7 @@ Action a_assemble_all_patches(
|
|||||||
Edition). The output files are saved in system/client-functions.\n",
|
Edition). The output files are saved in system/client-functions.\n",
|
||||||
+[](Arguments&) {
|
+[](Arguments&) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("functions");
|
s.compile_functions(false);
|
||||||
|
|
||||||
auto process_code = +[](shared_ptr<const CompiledFunctionCode> code,
|
auto process_code = +[](shared_ptr<const CompiledFunctionCode> code,
|
||||||
uint32_t checksum_addr,
|
uint32_t checksum_addr,
|
||||||
@@ -1556,7 +1558,9 @@ Action a_print_word_select_table(
|
|||||||
option is given, prints the token table sorted by canonical name.\n",
|
option is given, prints the token table sorted by canonical name.\n",
|
||||||
+[](Arguments& args) {
|
+[](Arguments& args) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("word_select_table");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_text_index(false);
|
||||||
|
s.load_word_select_table(false);
|
||||||
Version v;
|
Version v;
|
||||||
try {
|
try {
|
||||||
v = get_cli_version(args);
|
v = get_cli_version(args);
|
||||||
@@ -1613,7 +1617,10 @@ Action a_convert_rare_item_set(
|
|||||||
auto version = get_cli_version(args);
|
auto version = get_cli_version(args);
|
||||||
|
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("item_name_indexes");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_text_index(false);
|
||||||
|
s.load_item_definitions(false);
|
||||||
|
s.load_item_name_indexes(false);
|
||||||
|
|
||||||
string input_filename = args.get<string>(1, false);
|
string input_filename = args.get<string>(1, false);
|
||||||
if (input_filename.empty() || (input_filename == "-")) {
|
if (input_filename.empty() || (input_filename == "-")) {
|
||||||
@@ -1668,7 +1675,10 @@ Action a_describe_item(
|
|||||||
auto version = get_cli_version(args);
|
auto version = get_cli_version(args);
|
||||||
|
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("item_name_indexes");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_text_index(false);
|
||||||
|
s.load_item_definitions(false);
|
||||||
|
s.load_item_name_indexes(false);
|
||||||
auto name_index = s.item_name_index(version);
|
auto name_index = s.item_name_index(version);
|
||||||
|
|
||||||
ItemData item = name_index->parse_item_description(description);
|
ItemData item = name_index->parse_item_description(description);
|
||||||
@@ -1728,7 +1738,10 @@ Action a_describe_item(
|
|||||||
Action a_name_all_items(
|
Action a_name_all_items(
|
||||||
"name-all-items", nullptr, +[](Arguments&) {
|
"name-all-items", nullptr, +[](Arguments&) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("item_name_indexes");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_text_index(false);
|
||||||
|
s.load_item_definitions(false);
|
||||||
|
s.load_item_name_indexes(false);
|
||||||
|
|
||||||
set<uint32_t> all_primary_identifiers;
|
set<uint32_t> all_primary_identifiers;
|
||||||
for (const auto& index : s.item_name_indexes) {
|
for (const auto& index : s.item_name_indexes) {
|
||||||
@@ -1773,7 +1786,10 @@ Action a_name_all_items(
|
|||||||
Action a_print_item_parameter_tables(
|
Action a_print_item_parameter_tables(
|
||||||
"print-item-tables", nullptr, +[](Arguments&) {
|
"print-item-tables", nullptr, +[](Arguments&) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("item_name_indexes");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_text_index(false);
|
||||||
|
s.load_item_definitions(false);
|
||||||
|
s.load_item_name_indexes(false);
|
||||||
for (size_t v_s = 0; v_s < NUM_VERSIONS; v_s++) {
|
for (size_t v_s = 0; v_s < NUM_VERSIONS; v_s++) {
|
||||||
const auto& index = s.item_name_indexes.at(v_s);
|
const auto& index = s.item_name_indexes.at(v_s);
|
||||||
if (index) {
|
if (index) {
|
||||||
@@ -1793,7 +1809,7 @@ Action a_show_ep3_cards(
|
|||||||
bool one_line = args.get<bool>("one-line");
|
bool one_line = args.get<bool>("one-line");
|
||||||
|
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("ep3_data");
|
s.load_ep3_cards(false);
|
||||||
|
|
||||||
unique_ptr<BinaryTextSet> text_english;
|
unique_ptr<BinaryTextSet> text_english;
|
||||||
try {
|
try {
|
||||||
@@ -1843,8 +1859,9 @@ Action a_generate_ep3_cards_html(
|
|||||||
bool is_nte = (get_cli_version(args, Version::GC_EP3) == Version::GC_EP3_NTE);
|
bool is_nte = (get_cli_version(args, Version::GC_EP3) == Version::GC_EP3_NTE);
|
||||||
|
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("ep3_data");
|
s.load_patch_indexes(false);
|
||||||
s.load_objects_and_upstream_dependents("text_index");
|
s.load_text_index(false);
|
||||||
|
s.load_ep3_cards(false);
|
||||||
|
|
||||||
shared_ptr<const TextSet> text_english;
|
shared_ptr<const TextSet> text_english;
|
||||||
try {
|
try {
|
||||||
@@ -2007,7 +2024,8 @@ Action a_show_ep3_maps(
|
|||||||
config_log.info("Collecting Episode 3 data");
|
config_log.info("Collecting Episode 3 data");
|
||||||
|
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("ep3_data");
|
s.load_ep3_cards(false);
|
||||||
|
s.load_ep3_maps(false);
|
||||||
|
|
||||||
auto map_ids = s.ep3_map_index->all_numbers();
|
auto map_ids = s.ep3_map_index->all_numbers();
|
||||||
log_info("%zu maps", map_ids.size());
|
log_info("%zu maps", map_ids.size());
|
||||||
@@ -2031,7 +2049,8 @@ Action a_show_battle_params(
|
|||||||
in a human-readable format.\n",
|
in a human-readable format.\n",
|
||||||
+[](Arguments&) {
|
+[](Arguments&) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("battle_params");
|
s.load_patch_indexes(false);
|
||||||
|
s.load_battle_params(false);
|
||||||
|
|
||||||
fprintf(stdout, "Episode 1 multi\n");
|
fprintf(stdout, "Episode 1 multi\n");
|
||||||
s.battle_params->get_table(false, Episode::EP1).print(stdout);
|
s.battle_params->get_table(false, Episode::EP1).print(stdout);
|
||||||
@@ -2073,7 +2092,8 @@ Action a_find_rare_enemy_seeds(
|
|||||||
ServerState s("system/config.json");
|
ServerState s("system/config.json");
|
||||||
shared_ptr<const VersionedQuest> vq;
|
shared_ptr<const VersionedQuest> vq;
|
||||||
if (!quest_name.empty()) {
|
if (!quest_name.empty()) {
|
||||||
s.load_objects_and_upstream_dependents("quest_index");
|
s.load_config();
|
||||||
|
s.load_quest_index(false);
|
||||||
auto q = s.quest_index(version)->get(quest_name);
|
auto q = s.quest_index(version)->get(quest_name);
|
||||||
if (!q) {
|
if (!q) {
|
||||||
throw runtime_error("quest does not exist");
|
throw runtime_error("quest does not exist");
|
||||||
@@ -2083,11 +2103,11 @@ Action a_find_rare_enemy_seeds(
|
|||||||
throw runtime_error("quest version does not exist");
|
throw runtime_error("quest version does not exist");
|
||||||
}
|
}
|
||||||
} else if (version == Version::BB_V4) {
|
} else if (version == Version::BB_V4) {
|
||||||
s.load_objects_and_upstream_dependents("config");
|
s.load_config();
|
||||||
} else if (version == Version::PC_V2) {
|
} else if (version == Version::PC_V2) {
|
||||||
s.load_objects_and_upstream_dependents("patch_indexes");
|
s.load_patch_indexes(false);
|
||||||
} else {
|
} else {
|
||||||
s.load_objects_and_upstream_dependents("map_file_caches");
|
s.clear_map_file_caches();
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<const Map::RareEnemyRates> rare_rates;
|
shared_ptr<const Map::RareEnemyRates> rare_rates;
|
||||||
@@ -2265,7 +2285,8 @@ Action a_diff_dol_files(
|
|||||||
Action a_replay_ep3_battle_commands(
|
Action a_replay_ep3_battle_commands(
|
||||||
"replay-ep3-battle-commands", nullptr, +[](Arguments& args) {
|
"replay-ep3-battle-commands", nullptr, +[](Arguments& args) {
|
||||||
ServerState s;
|
ServerState s;
|
||||||
s.load_objects_and_upstream_dependents("ep3_data");
|
s.load_ep3_cards(false);
|
||||||
|
s.load_ep3_maps(false);
|
||||||
|
|
||||||
auto random_crypt = make_shared<PSOV2Encryption>(args.get<uint32_t>("seed", 0, Arguments::IntFormat::HEX));
|
auto random_crypt = make_shared<PSOV2Encryption>(args.get<uint32_t>("seed", 0, Arguments::IntFormat::HEX));
|
||||||
Episode3::Server::Options options = {
|
Episode3::Server::Options options = {
|
||||||
@@ -2296,6 +2317,15 @@ Action a_run_server_replay_log(
|
|||||||
config_log.info("newserv %s compiled at %s", GIT_REVISION_HASH, build_date.c_str());
|
config_log.info("newserv %s compiled at %s", GIT_REVISION_HASH, build_date.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PHOSG_WINDOWS
|
||||||
|
int evthread_ret = evthread_use_windows_threads();
|
||||||
|
#else
|
||||||
|
int evthread_ret = evthread_use_pthreads();
|
||||||
|
#endif
|
||||||
|
if (evthread_ret) {
|
||||||
|
throw runtime_error("failed to setup libevent threads");
|
||||||
|
}
|
||||||
|
|
||||||
if (!isdir("system/players")) {
|
if (!isdir("system/players")) {
|
||||||
config_log.info("Players directory does not exist; creating it");
|
config_log.info("Players directory does not exist; creating it");
|
||||||
mkdir("system/players", 0755);
|
mkdir("system/players", 0755);
|
||||||
@@ -2319,7 +2349,7 @@ Action a_run_server_replay_log(
|
|||||||
|
|
||||||
shared_ptr<struct event_base> base(event_base_new(), event_base_free);
|
shared_ptr<struct event_base> base(event_base_new(), event_base_free);
|
||||||
auto state = make_shared<ServerState>(base, config_filename, is_replay);
|
auto state = make_shared<ServerState>(base, config_filename, is_replay);
|
||||||
state->load_objects_and_downstream_dependents("all");
|
state->load_all();
|
||||||
|
|
||||||
shared_ptr<DNSServer> dns_server;
|
shared_ptr<DNSServer> dns_server;
|
||||||
if (state->dns_server_port && !is_replay) {
|
if (state->dns_server_port && !is_replay) {
|
||||||
@@ -2334,7 +2364,7 @@ Action a_run_server_replay_log(
|
|||||||
config_log.info("DNS server is disabled");
|
config_log.info("DNS server is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Shell> shell;
|
shared_ptr<ServerShell> shell;
|
||||||
shared_ptr<ReplaySession> replay_session;
|
shared_ptr<ReplaySession> replay_session;
|
||||||
shared_ptr<IPStackSimulator> ip_stack_simulator;
|
shared_ptr<IPStackSimulator> ip_stack_simulator;
|
||||||
if (is_replay) {
|
if (is_replay) {
|
||||||
@@ -2423,11 +2453,12 @@ Action a_run_server_replay_log(
|
|||||||
if (should_run_shell) {
|
if (should_run_shell) {
|
||||||
should_run_shell = !replay_session.get();
|
should_run_shell = !replay_session.get();
|
||||||
}
|
}
|
||||||
if (should_run_shell) {
|
|
||||||
shell = make_shared<ServerShell>(base, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_log.info("Ready");
|
config_log.info("Ready");
|
||||||
|
if (should_run_shell) {
|
||||||
|
shell = make_shared<ServerShell>(state);
|
||||||
|
}
|
||||||
|
|
||||||
event_base_dispatch(base.get());
|
event_base_dispatch(base.get());
|
||||||
if (replay_session) {
|
if (replay_session) {
|
||||||
// If in a replay session, run the event loop for a bit longer to make
|
// If in a replay session, run the event loop for a bit longer to make
|
||||||
|
|||||||
@@ -65,8 +65,10 @@ static shared_ptr<const Menu> proxy_options_menu_for_client(shared_ptr<const Cli
|
|||||||
"Block events", "Disable seasonal\nevents in the lobby\nand in games");
|
"Block events", "Disable seasonal\nevents in the lobby\nand in games");
|
||||||
add_flag_option(ProxyOptionsMenuItemID::BLOCK_PATCHES, Client::Flag::PROXY_BLOCK_FUNCTION_CALLS,
|
add_flag_option(ProxyOptionsMenuItemID::BLOCK_PATCHES, Client::Flag::PROXY_BLOCK_FUNCTION_CALLS,
|
||||||
"Block patches", "Disable patches sent\nby the remote server");
|
"Block patches", "Disable patches sent\nby the remote server");
|
||||||
add_flag_option(ProxyOptionsMenuItemID::SWITCH_ASSIST, Client::Flag::SWITCH_ASSIST_ENABLED,
|
if (!is_ep3(c->version())) {
|
||||||
"Switch assist", "Automatically try\nto unlock 2-player\ndoors when you step\non both switches\nsequentially");
|
add_flag_option(ProxyOptionsMenuItemID::SWITCH_ASSIST, Client::Flag::SWITCH_ASSIST_ENABLED,
|
||||||
|
"Switch assist", "Automatically try\nto unlock 2-player\ndoors when you step\non both switches\nsequentially");
|
||||||
|
}
|
||||||
if ((s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) || c->license->check_flag(License::Flag::CHEAT_ANYWHERE)) {
|
if ((s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) || c->license->check_flag(License::Flag::CHEAT_ANYWHERE)) {
|
||||||
if (!is_ep3(c->version())) {
|
if (!is_ep3(c->version())) {
|
||||||
add_flag_option(ProxyOptionsMenuItemID::INFINITE_HP, Client::Flag::INFINITE_HP_ENABLED,
|
add_flag_option(ProxyOptionsMenuItemID::INFINITE_HP, Client::Flag::INFINITE_HP_ENABLED,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "Loggers.hh"
|
#include "Loggers.hh"
|
||||||
#include "Server.hh"
|
#include "Server.hh"
|
||||||
#include "Shell.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -474,9 +473,6 @@ ReplaySession::ReplaySession(
|
|||||||
while (!feof(input_log)) {
|
while (!feof(input_log)) {
|
||||||
line_num++;
|
line_num++;
|
||||||
string line = fgets(input_log);
|
string line = fgets(input_log);
|
||||||
if (starts_with(line, Shell::PROMPT)) {
|
|
||||||
line = line.substr(Shell::PROMPT.size());
|
|
||||||
}
|
|
||||||
if (ends_with(line, "\n")) {
|
if (ends_with(line, "\n")) {
|
||||||
line.resize(line.size() - 1);
|
line.resize(line.size() - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -30,8 +30,7 @@ public:
|
|||||||
void disconnect_client(std::shared_ptr<Client> c);
|
void disconnect_client(std::shared_ptr<Client> c);
|
||||||
|
|
||||||
std::shared_ptr<Client> get_client() const;
|
std::shared_ptr<Client> get_client() const;
|
||||||
std::vector<std::shared_ptr<Client>> get_clients_by_identifier(
|
std::vector<std::shared_ptr<Client>> get_clients_by_identifier(const std::string& ident) const;
|
||||||
const std::string& ident) const;
|
|
||||||
std::shared_ptr<struct event_base> get_base() const;
|
std::shared_ptr<struct event_base> get_base() const;
|
||||||
|
|
||||||
inline std::shared_ptr<ServerState> get_state() const {
|
inline std::shared_ptr<ServerState> get_state() const {
|
||||||
@@ -69,8 +68,7 @@ private:
|
|||||||
evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx);
|
evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx);
|
||||||
static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx);
|
static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx);
|
||||||
|
|
||||||
void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd,
|
void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen);
|
||||||
struct sockaddr* address, int socklen);
|
|
||||||
void on_listen_error(struct evconnlistener* listener);
|
void on_listen_error(struct evconnlistener* listener);
|
||||||
|
|
||||||
static void on_client_input(Channel& ch, uint16_t command, uint32_t flag, std::string& data);
|
static void on_client_input(Channel& ch, uint16_t command, uint32_t flag, std::string& data);
|
||||||
|
|||||||
+718
-687
File diff suppressed because it is too large
Load Diff
+14
-13
@@ -6,27 +6,28 @@
|
|||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
|
|
||||||
#include "ProxyServer.hh"
|
#include "ProxyServer.hh"
|
||||||
#include "Shell.hh"
|
#include "ServerState.hh"
|
||||||
|
|
||||||
#define SHELL_PROMPT "newserv> "
|
class ServerShell : public std::enable_shared_from_this<ServerShell> {
|
||||||
|
|
||||||
class ServerShell : public Shell {
|
|
||||||
public:
|
public:
|
||||||
ServerShell(
|
class exit_shell : public std::runtime_error {
|
||||||
std::shared_ptr<struct event_base> base,
|
public:
|
||||||
std::shared_ptr<ServerState> state);
|
exit_shell();
|
||||||
virtual ~ServerShell() = default;
|
~exit_shell() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ServerShell(std::shared_ptr<ServerState> state);
|
||||||
ServerShell(const ServerShell&) = delete;
|
ServerShell(const ServerShell&) = delete;
|
||||||
ServerShell(ServerShell&&) = delete;
|
ServerShell(ServerShell&&) = delete;
|
||||||
ServerShell& operator=(const ServerShell&) = delete;
|
ServerShell& operator=(const ServerShell&) = delete;
|
||||||
ServerShell& operator=(ServerShell&&) = delete;
|
ServerShell& operator=(ServerShell&&) = delete;
|
||||||
|
~ServerShell();
|
||||||
|
|
||||||
|
std::shared_ptr<ProxyServer::LinkedSession> get_proxy_session(const std::string& name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<ServerState> state;
|
std::shared_ptr<ServerState> state;
|
||||||
|
std::thread th;
|
||||||
|
|
||||||
std::shared_ptr<ProxyServer::LinkedSession> get_proxy_session(
|
void thread_fn();
|
||||||
const std::string& name);
|
|
||||||
|
|
||||||
virtual void print_prompt();
|
|
||||||
virtual void execute_command(const std::string& command);
|
|
||||||
};
|
};
|
||||||
|
|||||||
+284
-225
@@ -7,6 +7,7 @@
|
|||||||
#include <phosg/Network.hh>
|
#include <phosg/Network.hh>
|
||||||
|
|
||||||
#include "Compression.hh"
|
#include "Compression.hh"
|
||||||
|
#include "EventUtils.hh"
|
||||||
#include "FileContentsCache.hh"
|
#include "FileContentsCache.hh"
|
||||||
#include "GVMEncoder.hh"
|
#include "GVMEncoder.hh"
|
||||||
#include "IPStackSimulator.hh"
|
#include "IPStackSimulator.hh"
|
||||||
@@ -32,9 +33,7 @@ ServerState::QuestF960Result::QuestF960Result(const JSON& json, std::shared_ptr<
|
|||||||
|
|
||||||
ServerState::ServerState(const string& config_filename)
|
ServerState::ServerState(const string& config_filename)
|
||||||
: creation_time(now()),
|
: creation_time(now()),
|
||||||
config_filename(config_filename) {
|
config_filename(config_filename) {}
|
||||||
this->create_load_step_graph();
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerState::ServerState(shared_ptr<struct event_base> base, const string& config_filename, bool is_replay)
|
ServerState::ServerState(shared_ptr<struct event_base> base, const string& config_filename, bool is_replay)
|
||||||
: creation_time(now()),
|
: creation_time(now()),
|
||||||
@@ -42,25 +41,7 @@ ServerState::ServerState(shared_ptr<struct event_base> base, const string& confi
|
|||||||
config_filename(config_filename),
|
config_filename(config_filename),
|
||||||
is_replay(is_replay),
|
is_replay(is_replay),
|
||||||
player_files_manager(this->base ? make_shared<PlayerFilesManager>(base) : nullptr),
|
player_files_manager(this->base ? make_shared<PlayerFilesManager>(base) : nullptr),
|
||||||
destroy_lobbies_event(this->base ? event_new(base.get(), -1, EV_TIMEOUT, &ServerState::dispatch_destroy_lobbies, this) : nullptr, event_free) {
|
destroy_lobbies_event(this->base ? event_new(base.get(), -1, EV_TIMEOUT, &ServerState::dispatch_destroy_lobbies, this) : nullptr, event_free) {}
|
||||||
this->create_load_step_graph();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerState::load_objects_and_downstream_dependents(const std::string& what) {
|
|
||||||
this->load_step_graph.run(what, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerState::load_objects_and_downstream_dependents(const std::vector<std::string>& what) {
|
|
||||||
this->load_step_graph.run(what, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerState::load_objects_and_upstream_dependents(const std::string& what) {
|
|
||||||
this->load_step_graph.run(what, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerState::load_objects_and_upstream_dependents(const std::vector<std::string>& what) {
|
|
||||||
this->load_step_graph.run(what, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerState::add_client_to_available_lobby(shared_ptr<Client> c) {
|
void ServerState::add_client_to_available_lobby(shared_ptr<Client> c) {
|
||||||
shared_ptr<Lobby> added_to_lobby;
|
shared_ptr<Lobby> added_to_lobby;
|
||||||
@@ -404,10 +385,6 @@ shared_ptr<const ItemParameterTable> ServerState::item_parameter_table_for_encod
|
|||||||
return this->item_parameter_table(is_v1(version) ? Version::PC_V2 : version);
|
return this->item_parameter_table(is_v1(version) ? Version::PC_V2 : version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::set_item_parameter_table(Version version, shared_ptr<const ItemParameterTable> table) {
|
|
||||||
this->item_parameter_tables.at(static_cast<size_t>(version)) = table;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_indexes.at(static_cast<size_t>(version));
|
||||||
if (ret == nullptr) {
|
if (ret == nullptr) {
|
||||||
@@ -416,10 +393,6 @@ shared_ptr<const ItemNameIndex> ServerState::item_name_index(Version version) co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::set_item_name_index(Version version, shared_ptr<const ItemNameIndex> new_index) {
|
|
||||||
this->item_name_indexes.at(static_cast<size_t>(version)) = new_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
|
string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
|
||||||
return this->item_name_index(version)->describe_item(item, include_color_codes);
|
return this->item_name_index(version)->describe_item(item, include_color_codes);
|
||||||
}
|
}
|
||||||
@@ -784,28 +757,32 @@ void ServerState::load_config() {
|
|||||||
for (auto& trap_card_ids : this->ep3_trap_card_ids) {
|
for (auto& trap_card_ids : this->ep3_trap_card_ids) {
|
||||||
trap_card_ids.clear();
|
trap_card_ids.clear();
|
||||||
}
|
}
|
||||||
try {
|
if (this->ep3_card_index) {
|
||||||
const auto& ep3_trap_cards_json = json.get_list("Episode3TrapCards");
|
try {
|
||||||
if (!ep3_trap_cards_json.empty()) {
|
const auto& ep3_trap_cards_json = json.get_list("Episode3TrapCards");
|
||||||
if (ep3_trap_cards_json.size() != 5) {
|
if (!ep3_trap_cards_json.empty()) {
|
||||||
throw runtime_error("Episode3TrapCards must be a list of 5 lists");
|
if (ep3_trap_cards_json.size() != 5) {
|
||||||
}
|
throw runtime_error("Episode3TrapCards must be a list of 5 lists");
|
||||||
for (size_t trap_type = 0; trap_type < 5; trap_type++) {
|
}
|
||||||
auto& trap_card_ids = this->ep3_trap_card_ids[trap_type];
|
for (size_t trap_type = 0; trap_type < 5; trap_type++) {
|
||||||
for (const auto& card_it : ep3_trap_cards_json.at(trap_type)->as_list()) {
|
auto& trap_card_ids = this->ep3_trap_card_ids[trap_type];
|
||||||
try {
|
for (const auto& card_it : ep3_trap_cards_json.at(trap_type)->as_list()) {
|
||||||
const auto& card = this->ep3_card_index->definition_for_name_normalized(card_it->as_string());
|
try {
|
||||||
if (card->def.type != Episode3::CardType::ASSIST) {
|
const auto& card = this->ep3_card_index->definition_for_name_normalized(card_it->as_string());
|
||||||
throw runtime_error(string_printf("Ep3 card \"%s\" in trap card list is not an assist card", name.c_str()));
|
if (card->def.type != Episode3::CardType::ASSIST) {
|
||||||
|
throw runtime_error(string_printf("Ep3 card \"%s\" in trap card list is not an assist card", name.c_str()));
|
||||||
|
}
|
||||||
|
trap_card_ids.emplace_back(card->def.card_id);
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
throw runtime_error(string_printf("Ep3 card \"%s\" in trap card list does not exist", name.c_str()));
|
||||||
}
|
}
|
||||||
trap_card_ids.emplace_back(card->def.card_id);
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
throw runtime_error(string_printf("Ep3 card \"%s\" in trap card list does not exist", name.c_str()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} else {
|
||||||
|
config_log.warning("Episode 3 card definitions missing; cannot set trap card IDs from config");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->is_replay) {
|
if (!this->is_replay) {
|
||||||
@@ -877,42 +854,46 @@ void ServerState::load_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->quest_F95E_results.clear();
|
this->quest_F95E_results.clear();
|
||||||
try {
|
|
||||||
for (const auto& type_it : json.get_list("QuestF95EResultItems")) {
|
|
||||||
auto& type_res = this->quest_F95E_results.emplace_back();
|
|
||||||
for (const auto& difficulty_it : type_it->as_list()) {
|
|
||||||
auto& difficulty_res = type_res.emplace_back();
|
|
||||||
for (const auto& item_it : difficulty_it->as_list()) {
|
|
||||||
difficulty_res.emplace_back(this->parse_item_description(Version::BB_V4, item_it->as_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
}
|
|
||||||
this->quest_F95F_results.clear();
|
this->quest_F95F_results.clear();
|
||||||
try {
|
|
||||||
for (const auto& it : json.get_list("QuestF95FResultItems")) {
|
|
||||||
auto& list = it->as_list();
|
|
||||||
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())));
|
|
||||||
}
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
}
|
|
||||||
this->quest_F960_success_results.clear();
|
this->quest_F960_success_results.clear();
|
||||||
this->quest_F960_failure_results = QuestF960Result();
|
this->quest_F960_failure_results = QuestF960Result();
|
||||||
try {
|
|
||||||
this->quest_F960_failure_results = QuestF960Result(json.at("QuestF960FailureResultItems"), this->item_name_index(Version::BB_V4));
|
|
||||||
for (const auto& it : json.get_list("QuestF960SuccessResultItems")) {
|
|
||||||
this->quest_F960_success_results.emplace_back(*it, this->item_name_index(Version::BB_V4));
|
|
||||||
}
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
}
|
|
||||||
this->secret_lottery_results.clear();
|
this->secret_lottery_results.clear();
|
||||||
try {
|
if (this->item_name_index(Version::BB_V4)) {
|
||||||
for (const auto& it : json.get_list("SecretLotteryResultItems")) {
|
try {
|
||||||
this->secret_lottery_results.emplace_back(this->parse_item_description(Version::BB_V4, it->as_string()));
|
for (const auto& type_it : json.get_list("QuestF95EResultItems")) {
|
||||||
|
auto& type_res = this->quest_F95E_results.emplace_back();
|
||||||
|
for (const auto& difficulty_it : type_it->as_list()) {
|
||||||
|
auto& difficulty_res = type_res.emplace_back();
|
||||||
|
for (const auto& item_it : difficulty_it->as_list()) {
|
||||||
|
difficulty_res.emplace_back(this->parse_item_description(Version::BB_V4, item_it->as_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
try {
|
||||||
|
for (const auto& it : json.get_list("QuestF95FResultItems")) {
|
||||||
|
auto& list = it->as_list();
|
||||||
|
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())));
|
||||||
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this->quest_F960_failure_results = QuestF960Result(json.at("QuestF960FailureResultItems"), this->item_name_index(Version::BB_V4));
|
||||||
|
for (const auto& it : json.get_list("QuestF960SuccessResultItems")) {
|
||||||
|
this->quest_F960_success_results.emplace_back(*it, this->item_name_index(Version::BB_V4));
|
||||||
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (const auto& it : json.get_list("SecretLotteryResultItems")) {
|
||||||
|
this->secret_lottery_results.emplace_back(this->parse_item_description(Version::BB_V4, it->as_string()));
|
||||||
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config_log.warning("BB item name index is missing; cannot load quest reward lists from config");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->bb_global_exp_multiplier = json.get_int("BBGlobalEXPMultiplier", 1);
|
this->bb_global_exp_multiplier = json.get_int("BBGlobalEXPMultiplier", 1);
|
||||||
@@ -958,6 +939,7 @@ void ServerState::load_config() {
|
|||||||
const auto& l = this->find_lobby(z + 1);
|
const auto& l = this->find_lobby(z + 1);
|
||||||
if (l && l->check_flag(Lobby::Flag::DEFAULT)) {
|
if (l && l->check_flag(Lobby::Flag::DEFAULT)) {
|
||||||
l->event = event;
|
l->event = event;
|
||||||
|
send_change_event(l, l->event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
@@ -1133,41 +1115,61 @@ void ServerState::load_config() {
|
|||||||
this->config_loaded = true;
|
this->config_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_bb_private_keys() {
|
void ServerState::load_bb_private_keys(bool from_non_event_thread) {
|
||||||
|
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> new_keys;
|
||||||
for (const string& filename : list_directory("system/blueburst/keys")) {
|
for (const string& filename : list_directory("system/blueburst/keys")) {
|
||||||
if (!ends_with(filename, ".nsk")) {
|
if (!ends_with(filename, ".nsk")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this->bb_private_keys.emplace_back(make_shared<PSOBBEncryption::KeyFile>(
|
new_keys.emplace_back(make_shared<PSOBBEncryption::KeyFile>(
|
||||||
load_object_file<PSOBBEncryption::KeyFile>("system/blueburst/keys/" + filename)));
|
load_object_file<PSOBBEncryption::KeyFile>("system/blueburst/keys/" + filename)));
|
||||||
config_log.info("Loaded Blue Burst key file: %s", filename.c_str());
|
config_log.info("Loaded Blue Burst key file: %s", filename.c_str());
|
||||||
}
|
}
|
||||||
config_log.info("%zu Blue Burst key file(s) loaded", this->bb_private_keys.size());
|
config_log.info("%zu Blue Burst key file(s) loaded", this->bb_private_keys.size());
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_keys = std::move(new_keys)]() {
|
||||||
|
s->bb_private_keys = std::move(new_keys);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_licenses() {
|
void ServerState::load_licenses(bool from_non_event_thread) {
|
||||||
config_log.info("Indexing licenses");
|
config_log.info("Indexing licenses");
|
||||||
this->license_index = this->is_replay ? make_shared<LicenseIndex>() : make_shared<DiskLicenseIndex>();
|
shared_ptr<LicenseIndex> new_index = this->is_replay ? make_shared<LicenseIndex>() : make_shared<DiskLicenseIndex>();
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_index = std::move(new_index)]() {
|
||||||
|
s->license_index = std::move(new_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_teams() {
|
void ServerState::load_teams(bool from_non_event_thread) {
|
||||||
config_log.info("Indexing teams");
|
config_log.info("Indexing teams");
|
||||||
this->team_index = make_shared<TeamIndex>("system/teams", this->team_reward_defs_json);
|
shared_ptr<TeamIndex> new_index = make_shared<TeamIndex>("system/teams", this->team_reward_defs_json);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_index = std::move(new_index)]() {
|
||||||
|
s->team_index = std::move(new_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_patch_indexes() {
|
void ServerState::load_patch_indexes(bool from_non_event_thread) {
|
||||||
|
shared_ptr<const GSLArchive> bb_data_gsl;
|
||||||
|
shared_ptr<PatchFileIndex> pc_patch_file_index;
|
||||||
|
shared_ptr<PatchFileIndex> bb_patch_file_index;
|
||||||
|
|
||||||
if (isdir("system/patch-pc")) {
|
if (isdir("system/patch-pc")) {
|
||||||
config_log.info("Indexing PSO PC patch files");
|
config_log.info("Indexing PSO PC patch files");
|
||||||
this->pc_patch_file_index = make_shared<PatchFileIndex>("system/patch-pc");
|
pc_patch_file_index = make_shared<PatchFileIndex>("system/patch-pc");
|
||||||
} else {
|
} else {
|
||||||
config_log.info("PSO PC patch files not present");
|
config_log.info("PSO PC patch files not present");
|
||||||
}
|
}
|
||||||
if (isdir("system/patch-bb")) {
|
if (isdir("system/patch-bb")) {
|
||||||
config_log.info("Indexing PSO BB patch files");
|
config_log.info("Indexing PSO BB patch files");
|
||||||
this->bb_patch_file_index = make_shared<PatchFileIndex>("system/patch-bb");
|
bb_patch_file_index = make_shared<PatchFileIndex>("system/patch-bb");
|
||||||
try {
|
try {
|
||||||
auto gsl_file = this->bb_patch_file_index->get("./data/data.gsl");
|
auto gsl_file = bb_patch_file_index->get("./data/data.gsl");
|
||||||
this->bb_data_gsl = make_shared<GSLArchive>(gsl_file->load_data(), false);
|
bb_data_gsl = make_shared<GSLArchive>(gsl_file->load_data(), false);
|
||||||
config_log.info("data.gsl found in BB patch files");
|
config_log.info("data.gsl found in BB patch files");
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
config_log.info("data.gsl is not present in BB patch files");
|
config_log.info("data.gsl is not present in BB patch files");
|
||||||
@@ -1175,6 +1177,16 @@ void ServerState::load_patch_indexes() {
|
|||||||
} else {
|
} else {
|
||||||
config_log.info("PSO BB patch files not present");
|
config_log.info("PSO BB patch files not present");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
bb_data_gsl = std::move(bb_data_gsl),
|
||||||
|
pc_patch_file_index = std::move(pc_patch_file_index),
|
||||||
|
bb_patch_file_index = std::move(bb_patch_file_index)]() {
|
||||||
|
s->bb_data_gsl = std::move(bb_data_gsl);
|
||||||
|
s->pc_patch_file_index = std::move(pc_patch_file_index);
|
||||||
|
s->bb_patch_file_index = std::move(bb_patch_file_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::clear_map_file_caches() {
|
void ServerState::clear_map_file_caches() {
|
||||||
@@ -1184,21 +1196,25 @@ void ServerState::clear_map_file_caches() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_set_data_tables() {
|
void ServerState::load_set_data_tables(bool from_non_event_thread) {
|
||||||
config_log.info("Loading set data tables");
|
config_log.info("Loading set data tables");
|
||||||
std::array<std::shared_ptr<const SetDataTableBase>, NUM_VERSIONS> set_data_tables;
|
|
||||||
|
|
||||||
auto load_table = [this](Version version) -> void {
|
std::array<std::shared_ptr<const SetDataTableBase>, NUM_VERSIONS> new_tables;
|
||||||
|
std::array<std::shared_ptr<const SetDataTableBase>, NUM_VERSIONS> new_tables_ep1_ult;
|
||||||
|
std::shared_ptr<const SetDataTableBase> new_table_bb_solo;
|
||||||
|
std::shared_ptr<const SetDataTableBase> new_table_bb_solo_ep1_ult;
|
||||||
|
|
||||||
|
auto load_table = [&](Version version) -> void {
|
||||||
auto data = this->load_map_file(version, "SetDataTableOn.rel");
|
auto data = this->load_map_file(version, "SetDataTableOn.rel");
|
||||||
this->set_data_tables[static_cast<size_t>(version)] = make_shared<SetDataTable>(version, *data);
|
new_tables[static_cast<size_t>(version)] = make_shared<SetDataTable>(version, *data);
|
||||||
if (!is_v1(version) && (version != Version::PC_NTE)) {
|
if (!is_v1(version) && (version != Version::PC_NTE)) {
|
||||||
auto data_ep1_ult = this->load_map_file(version, "SetDataTableOnUlti.rel");
|
auto data_ep1_ult = this->load_map_file(version, "SetDataTableOnUlti.rel");
|
||||||
this->set_data_tables_ep1_ult[static_cast<size_t>(version)] = make_shared<SetDataTable>(version, *data_ep1_ult);
|
new_tables_ep1_ult[static_cast<size_t>(version)] = make_shared<SetDataTable>(version, *data_ep1_ult);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this->set_data_tables[static_cast<size_t>(Version::DC_NTE)] = make_shared<SetDataTableDCNTE>();
|
new_tables[static_cast<size_t>(Version::DC_NTE)] = make_shared<SetDataTableDCNTE>();
|
||||||
this->set_data_tables[static_cast<size_t>(Version::DC_V1_11_2000_PROTOTYPE)] = make_shared<SetDataTableDC112000>();
|
new_tables[static_cast<size_t>(Version::DC_V1_11_2000_PROTOTYPE)] = make_shared<SetDataTableDC112000>();
|
||||||
load_table(Version::DC_V1);
|
load_table(Version::DC_V1);
|
||||||
load_table(Version::DC_V2);
|
load_table(Version::DC_V2);
|
||||||
load_table(Version::PC_NTE);
|
load_table(Version::PC_NTE);
|
||||||
@@ -1209,29 +1225,51 @@ void ServerState::load_set_data_tables() {
|
|||||||
load_table(Version::BB_V4);
|
load_table(Version::BB_V4);
|
||||||
|
|
||||||
auto bb_solo_data = this->load_map_file(Version::BB_V4, "SetDataTableOff.rel");
|
auto bb_solo_data = this->load_map_file(Version::BB_V4, "SetDataTableOff.rel");
|
||||||
this->bb_solo_set_data_table = make_shared<SetDataTable>(Version::BB_V4, *bb_solo_data);
|
new_table_bb_solo = make_shared<SetDataTable>(Version::BB_V4, *bb_solo_data);
|
||||||
auto bb_solo_data_ep1_ult = this->load_map_file(Version::BB_V4, "SetDataTableOffUlti.rel");
|
auto bb_solo_data_ep1_ult = this->load_map_file(Version::BB_V4, "SetDataTableOffUlti.rel");
|
||||||
this->bb_solo_set_data_table_ep1_ult = make_shared<SetDataTable>(Version::BB_V4, *bb_solo_data_ep1_ult);
|
new_table_bb_solo_ep1_ult = make_shared<SetDataTable>(Version::BB_V4, *bb_solo_data_ep1_ult);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
new_tables = std::move(new_tables),
|
||||||
|
new_tables_ep1_ult = std::move(new_tables_ep1_ult),
|
||||||
|
new_table_bb_solo = std::move(new_table_bb_solo),
|
||||||
|
new_table_bb_solo_ep1_ult = std::move(new_table_bb_solo_ep1_ult)]() {
|
||||||
|
s->set_data_tables = std::move(new_tables);
|
||||||
|
s->set_data_tables_ep1_ult = std::move(new_tables_ep1_ult);
|
||||||
|
s->bb_solo_set_data_table = std::move(new_table_bb_solo);
|
||||||
|
s->bb_solo_set_data_table_ep1_ult = std::move(new_table_bb_solo_ep1_ult);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_battle_params() {
|
void ServerState::load_battle_params(bool from_non_event_thread) {
|
||||||
config_log.info("Loading battle parameters");
|
config_log.info("Loading battle parameters");
|
||||||
this->battle_params = make_shared<BattleParamsIndex>(
|
auto new_battle_params = make_shared<BattleParamsIndex>(
|
||||||
this->load_bb_file("BattleParamEntry_on.dat"),
|
this->load_bb_file("BattleParamEntry_on.dat"),
|
||||||
this->load_bb_file("BattleParamEntry_lab_on.dat"),
|
this->load_bb_file("BattleParamEntry_lab_on.dat"),
|
||||||
this->load_bb_file("BattleParamEntry_ep4_on.dat"),
|
this->load_bb_file("BattleParamEntry_ep4_on.dat"),
|
||||||
this->load_bb_file("BattleParamEntry.dat"),
|
this->load_bb_file("BattleParamEntry.dat"),
|
||||||
this->load_bb_file("BattleParamEntry_lab.dat"),
|
this->load_bb_file("BattleParamEntry_lab.dat"),
|
||||||
this->load_bb_file("BattleParamEntry_ep4.dat"));
|
this->load_bb_file("BattleParamEntry_ep4.dat"));
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_battle_params = std::move(new_battle_params)]() {
|
||||||
|
s->battle_params = std::move(new_battle_params);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_level_table() {
|
void ServerState::load_level_table(bool from_non_event_thread) {
|
||||||
config_log.info("Loading level table");
|
config_log.info("Loading level table");
|
||||||
this->level_table = make_shared<LevelTableV4>(*this->load_bb_file("PlyLevelTbl.prs"), true);
|
auto new_table = make_shared<LevelTableV4>(*this->load_bb_file("PlyLevelTbl.prs"), true);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_table = std::move(new_table)]() {
|
||||||
|
s->level_table = std::move(new_table);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_text_index() {
|
void ServerState::load_text_index(bool from_non_event_thread) {
|
||||||
this->text_index = make_shared<TextIndex>("system/text-sets", [&](Version version, const string& filename) -> shared_ptr<const string> {
|
auto new_index = make_shared<TextIndex>("system/text-sets", [&](Version version, const string& filename) -> shared_ptr<const string> {
|
||||||
try {
|
try {
|
||||||
if (version == Version::BB_V4) {
|
if (version == Version::BB_V4) {
|
||||||
return this->load_bb_file(filename);
|
return this->load_bb_file(filename);
|
||||||
@@ -1244,9 +1282,14 @@ void ServerState::load_text_index() {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_index = std::move(new_index)]() {
|
||||||
|
s->text_index = std::move(new_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_word_select_table() {
|
void ServerState::load_word_select_table(bool from_non_event_thread) {
|
||||||
config_log.info("Loading Word Select table");
|
config_log.info("Loading Word Select table");
|
||||||
|
|
||||||
vector<vector<string>> name_alias_lists;
|
vector<vector<string>> name_alias_lists;
|
||||||
@@ -1299,11 +1342,16 @@ void ServerState::load_word_select_table() {
|
|||||||
WordSelectSet bb_v4_ws(load_file("system/text-sets/bb-v4/ws_data.bin"), Version::BB_V4, bb_unitxt_collection, false);
|
WordSelectSet bb_v4_ws(load_file("system/text-sets/bb-v4/ws_data.bin"), Version::BB_V4, bb_unitxt_collection, false);
|
||||||
|
|
||||||
config_log.info("(Word select) Generating table");
|
config_log.info("(Word select) Generating table");
|
||||||
this->word_select_table = make_shared<WordSelectTable>(
|
auto new_table = make_shared<WordSelectTable>(
|
||||||
dc_nte_ws, dc_112000_ws, dc_v1_ws, dc_v2_ws,
|
dc_nte_ws, dc_112000_ws, dc_v1_ws, dc_v2_ws,
|
||||||
pc_nte_ws, pc_v2_ws, gc_nte_ws, gc_v3_ws,
|
pc_nte_ws, pc_v2_ws, gc_nte_ws, gc_v3_ws,
|
||||||
gc_ep3_nte_ws, gc_ep3_ws, xb_v3_ws, bb_v4_ws,
|
gc_ep3_nte_ws, gc_ep3_ws, xb_v3_ws, bb_v4_ws,
|
||||||
name_alias_lists);
|
name_alias_lists);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_table = std::move(new_table)]() {
|
||||||
|
s->word_select_table = std::move(new_table);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ItemNameIndex> ServerState::create_item_name_index_for_version(
|
shared_ptr<ItemNameIndex> ServerState::create_item_name_index_for_version(
|
||||||
@@ -1334,16 +1382,24 @@ shared_ptr<ItemNameIndex> ServerState::create_item_name_index_for_version(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_item_name_indexes() {
|
void ServerState::load_item_name_indexes(bool from_non_event_thread) {
|
||||||
|
std::array<std::shared_ptr<const ItemNameIndex>, NUM_VERSIONS> new_indexes;
|
||||||
|
|
||||||
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++) {
|
||||||
Version v = static_cast<Version>(v_s);
|
Version v = static_cast<Version>(v_s);
|
||||||
config_log.info("Generating item name index for %s", name_for_enum(v));
|
config_log.info("Generating item name index for %s", name_for_enum(v));
|
||||||
this->set_item_name_index(v, this->create_item_name_index_for_version(v, this->item_parameter_table(v), this->text_index));
|
new_indexes[v_s] = this->create_item_name_index_for_version(v, this->item_parameter_table(v), this->text_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_indexes = std::move(new_indexes)]() {
|
||||||
|
s->item_name_indexes = std::move(new_indexes);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_drop_tables() {
|
void ServerState::load_drop_tables(bool from_non_event_thread) {
|
||||||
config_log.info("Loading rare item sets");
|
config_log.info("Loading rare item sets");
|
||||||
|
|
||||||
unordered_map<string, shared_ptr<const RareItemSet>> new_rare_item_sets;
|
unordered_map<string, shared_ptr<const RareItemSet>> new_rare_item_sets;
|
||||||
for (const auto& filename : list_directory_sorted("system/item-tables")) {
|
for (const auto& filename : list_directory_sorted("system/item-tables")) {
|
||||||
if (!starts_with(filename, "rare-table-")) {
|
if (!starts_with(filename, "rare-table-")) {
|
||||||
@@ -1387,25 +1443,25 @@ void ServerState::load_drop_tables() {
|
|||||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(load_file(path), true));
|
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(load_file(path), true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->rare_item_sets.swap(new_rare_item_sets);
|
|
||||||
|
|
||||||
config_log.info("Loading v2 common item table");
|
config_log.info("Loading v2 common item table");
|
||||||
auto ct_data_v2 = make_shared<string>(load_file("system/item-tables/ItemCT-pc-v2.afs"));
|
auto ct_data_v2 = make_shared<string>(load_file("system/item-tables/ItemCT-pc-v2.afs"));
|
||||||
auto pt_data_v2 = make_shared<string>(load_file("system/item-tables/ItemPT-pc-v2.afs"));
|
auto pt_data_v2 = make_shared<string>(load_file("system/item-tables/ItemPT-pc-v2.afs"));
|
||||||
this->common_item_set_v2 = make_shared<AFSV2CommonItemSet>(pt_data_v2, ct_data_v2);
|
auto new_common_item_set_v2 = make_shared<AFSV2CommonItemSet>(pt_data_v2, ct_data_v2);
|
||||||
config_log.info("Loading v3+v4 common item table");
|
config_log.info("Loading v3+v4 common item table");
|
||||||
auto pt_data_v3_v4 = make_shared<string>(load_file("system/item-tables/ItemPT-gc-v3.gsl"));
|
auto pt_data_v3_v4 = make_shared<string>(load_file("system/item-tables/ItemPT-gc-v3.gsl"));
|
||||||
this->common_item_set_v3_v4 = make_shared<GSLV3V4CommonItemSet>(pt_data_v3_v4, true);
|
auto new_common_item_set_v3_v4 = make_shared<GSLV3V4CommonItemSet>(pt_data_v3_v4, true);
|
||||||
|
|
||||||
config_log.info("Loading armor table");
|
config_log.info("Loading armor table");
|
||||||
auto armor_data = make_shared<string>(load_file("system/item-tables/ArmorRandom-gc-v3.rel"));
|
auto armor_data = make_shared<string>(load_file("system/item-tables/ArmorRandom-gc-v3.rel"));
|
||||||
this->armor_random_set = make_shared<ArmorRandomSet>(armor_data);
|
auto new_armor_random_set = make_shared<ArmorRandomSet>(armor_data);
|
||||||
|
|
||||||
config_log.info("Loading tool table");
|
config_log.info("Loading tool table");
|
||||||
auto tool_data = make_shared<string>(load_file("system/item-tables/ToolRandom-gc-v3.rel"));
|
auto tool_data = make_shared<string>(load_file("system/item-tables/ToolRandom-gc-v3.rel"));
|
||||||
this->tool_random_set = make_shared<ToolRandomSet>(tool_data);
|
auto new_tool_random_set = make_shared<ToolRandomSet>(tool_data);
|
||||||
|
|
||||||
config_log.info("Loading weapon tables");
|
config_log.info("Loading weapon tables");
|
||||||
|
std::array<std::shared_ptr<const WeaponRandomSet>, 4> new_weapon_random_sets;
|
||||||
const char* filenames[4] = {
|
const char* filenames[4] = {
|
||||||
"system/item-tables/WeaponRandomNormal-gc-v3.rel",
|
"system/item-tables/WeaponRandomNormal-gc-v3.rel",
|
||||||
"system/item-tables/WeaponRandomHard-gc-v3.rel",
|
"system/item-tables/WeaponRandomHard-gc-v3.rel",
|
||||||
@@ -1414,34 +1470,59 @@ void ServerState::load_drop_tables() {
|
|||||||
};
|
};
|
||||||
for (size_t z = 0; z < 4; z++) {
|
for (size_t z = 0; z < 4; z++) {
|
||||||
auto weapon_data = make_shared<string>(load_file(filenames[z]));
|
auto weapon_data = make_shared<string>(load_file(filenames[z]));
|
||||||
this->weapon_random_sets[z] = make_shared<WeaponRandomSet>(weapon_data);
|
new_weapon_random_sets[z] = make_shared<WeaponRandomSet>(weapon_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
config_log.info("Loading tekker adjustment table");
|
config_log.info("Loading tekker adjustment table");
|
||||||
auto tekker_data = make_shared<string>(load_file("system/item-tables/JudgeItem-gc-v3.rel"));
|
auto tekker_data = make_shared<string>(load_file("system/item-tables/JudgeItem-gc-v3.rel"));
|
||||||
this->tekker_adjustment_set = make_shared<TekkerAdjustmentSet>(tekker_data);
|
auto new_tekker_adjustment_set = make_shared<TekkerAdjustmentSet>(tekker_data);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
new_rare_item_sets = std::move(new_rare_item_sets),
|
||||||
|
new_common_item_set_v2 = std::move(new_common_item_set_v2),
|
||||||
|
new_common_item_set_v3_v4 = std::move(new_common_item_set_v3_v4),
|
||||||
|
new_armor_random_set = std::move(new_armor_random_set),
|
||||||
|
new_tool_random_set = std::move(new_tool_random_set),
|
||||||
|
new_weapon_random_sets = std::move(new_weapon_random_sets),
|
||||||
|
new_tekker_adjustment_set = std::move(new_tekker_adjustment_set)]() {
|
||||||
|
s->rare_item_sets = std::move(new_rare_item_sets);
|
||||||
|
s->common_item_set_v2 = std::move(new_common_item_set_v2);
|
||||||
|
s->common_item_set_v3_v4 = std::move(new_common_item_set_v3_v4);
|
||||||
|
s->armor_random_set = std::move(new_armor_random_set);
|
||||||
|
s->tool_random_set = std::move(new_tool_random_set);
|
||||||
|
s->weapon_random_sets = std::move(new_weapon_random_sets);
|
||||||
|
s->tekker_adjustment_set = std::move(new_tekker_adjustment_set);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_item_definitions() {
|
void ServerState::load_item_definitions(bool from_non_event_thread) {
|
||||||
|
std::array<std::shared_ptr<const ItemParameterTable>, NUM_VERSIONS> new_item_parameter_tables;
|
||||||
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++) {
|
||||||
Version v = static_cast<Version>(v_s);
|
Version v = static_cast<Version>(v_s);
|
||||||
string path = string_printf("system/item-tables/ItemPMT-%s.prs", file_path_token_for_version(v));
|
string path = string_printf("system/item-tables/ItemPMT-%s.prs", file_path_token_for_version(v));
|
||||||
config_log.info("Loading item definition table %s", path.c_str());
|
config_log.info("Loading item definition table %s", path.c_str());
|
||||||
auto data = make_shared<string>(prs_decompress(load_file(path)));
|
auto data = make_shared<string>(prs_decompress(load_file(path)));
|
||||||
this->set_item_parameter_table(v, make_shared<ItemParameterTable>(data, v));
|
new_item_parameter_tables[v_s] = make_shared<ItemParameterTable>(data, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should probably load the tables for other versions too.
|
// TODO: We should probably load the tables for other versions too.
|
||||||
config_log.info("Loading mag evolution table");
|
config_log.info("Loading mag evolution table");
|
||||||
auto mag_data = make_shared<string>(prs_decompress(load_file("system/item-tables/ItemMagEdit-bb-v4.prs")));
|
auto mag_data = make_shared<string>(prs_decompress(load_file("system/item-tables/ItemMagEdit-bb-v4.prs")));
|
||||||
this->mag_evolution_table = make_shared<MagEvolutionTable>(mag_data);
|
auto new_mag_evolution_table = make_shared<MagEvolutionTable>(mag_data);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
new_item_parameter_tables = std::move(new_item_parameter_tables),
|
||||||
|
new_mag_evolution_table = std::move(new_mag_evolution_table)]() {
|
||||||
|
s->item_parameter_tables = std::move(new_item_parameter_tables);
|
||||||
|
s->mag_evolution_table = std::move(new_mag_evolution_table);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_ep3_data() {
|
void ServerState::load_ep3_cards(bool from_non_event_thread) {
|
||||||
config_log.info("Collecting Episode 3 maps");
|
|
||||||
this->ep3_map_index = make_shared<Episode3::MapIndex>("system/ep3/maps");
|
|
||||||
config_log.info("Loading Episode 3 card definitions");
|
config_log.info("Loading Episode 3 card definitions");
|
||||||
this->ep3_card_index = make_shared<Episode3::CardIndex>(
|
auto new_ep3_card_index = make_shared<Episode3::CardIndex>(
|
||||||
"system/ep3/card-definitions.mnr",
|
"system/ep3/card-definitions.mnr",
|
||||||
"system/ep3/card-definitions.mnrd",
|
"system/ep3/card-definitions.mnrd",
|
||||||
"system/ep3/card-text.mnr",
|
"system/ep3/card-text.mnr",
|
||||||
@@ -1449,7 +1530,7 @@ void ServerState::load_ep3_data() {
|
|||||||
"system/ep3/card-dice-text.mnr",
|
"system/ep3/card-dice-text.mnr",
|
||||||
"system/ep3/card-dice-text.mnrd");
|
"system/ep3/card-dice-text.mnrd");
|
||||||
config_log.info("Loading Episode 3 trial card definitions");
|
config_log.info("Loading Episode 3 trial card definitions");
|
||||||
this->ep3_card_index_trial = make_shared<Episode3::CardIndex>(
|
auto new_ep3_card_index_trial = make_shared<Episode3::CardIndex>(
|
||||||
"system/ep3/card-definitions-trial.mnr",
|
"system/ep3/card-definitions-trial.mnr",
|
||||||
"system/ep3/card-definitions-trial.mnrd",
|
"system/ep3/card-definitions-trial.mnrd",
|
||||||
"system/ep3/card-text-trial.mnr",
|
"system/ep3/card-text-trial.mnr",
|
||||||
@@ -1457,39 +1538,76 @@ void ServerState::load_ep3_data() {
|
|||||||
"system/ep3/card-dice-text-trial.mnr",
|
"system/ep3/card-dice-text-trial.mnr",
|
||||||
"system/ep3/card-dice-text-trial.mnrd");
|
"system/ep3/card-dice-text-trial.mnrd");
|
||||||
config_log.info("Loading Episode 3 COM decks");
|
config_log.info("Loading Episode 3 COM decks");
|
||||||
this->ep3_com_deck_index = make_shared<Episode3::COMDeckIndex>("system/ep3/com-decks.json");
|
auto new_ep3_com_deck_index = make_shared<Episode3::COMDeckIndex>("system/ep3/com-decks.json");
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
new_ep3_card_index = std::move(new_ep3_card_index),
|
||||||
|
new_ep3_card_index_trial = std::move(new_ep3_card_index_trial),
|
||||||
|
new_ep3_com_deck_index = std::move(new_ep3_com_deck_index)]() {
|
||||||
|
s->ep3_card_index = std::move(new_ep3_card_index);
|
||||||
|
s->ep3_card_index_trial = std::move(new_ep3_card_index_trial);
|
||||||
|
s->ep3_com_deck_index = std::move(new_ep3_com_deck_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerState::load_ep3_maps(bool from_non_event_thread) {
|
||||||
|
config_log.info("Collecting Episode 3 maps");
|
||||||
|
auto new_ep3_map_index = make_shared<Episode3::MapIndex>("system/ep3/maps");
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_ep3_map_index = std::move(new_ep3_map_index)]() {
|
||||||
|
s->ep3_map_index = std::move(new_ep3_map_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerState::load_ep3_tournament_state(bool from_non_event_thread) {
|
||||||
|
config_log.info("Loading Episode 3 tournament state");
|
||||||
const string& tournament_state_filename = "system/ep3/tournament-state.json";
|
const string& tournament_state_filename = "system/ep3/tournament-state.json";
|
||||||
this->ep3_tournament_index = make_shared<Episode3::TournamentIndex>(
|
auto new_ep3_tournament_index = make_shared<Episode3::TournamentIndex>(
|
||||||
this->ep3_map_index, this->ep3_com_deck_index, tournament_state_filename);
|
this->ep3_map_index, this->ep3_com_deck_index, tournament_state_filename);
|
||||||
|
|
||||||
shared_ptr<ServerState> s;
|
auto set = [s = this->shared_from_this(),
|
||||||
try {
|
new_ep3_tournament_index = std::move(new_ep3_tournament_index)]() {
|
||||||
s = this->shared_from_this();
|
s->ep3_tournament_index = std::move(new_ep3_tournament_index);
|
||||||
} catch (const bad_weak_ptr&) {
|
s->ep3_tournament_index->link_all_clients(s);
|
||||||
}
|
};
|
||||||
if (s) {
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
this->ep3_tournament_index->link_all_clients(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_log.info("Loaded Episode 3 tournament state");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_quest_index() {
|
void ServerState::load_quest_index(bool from_non_event_thread) {
|
||||||
config_log.info("Collecting quests");
|
config_log.info("Collecting quests");
|
||||||
this->default_quest_index = make_shared<QuestIndex>("system/quests", this->quest_category_index, false);
|
auto new_default_quest_index = make_shared<QuestIndex>("system/quests", this->quest_category_index, false);
|
||||||
config_log.info("Collecting Episode 3 download quests");
|
config_log.info("Collecting Episode 3 download quests");
|
||||||
this->ep3_download_quest_index = make_shared<QuestIndex>("system/ep3/maps-download", this->quest_category_index, true);
|
auto new_ep3_download_quest_index = make_shared<QuestIndex>("system/ep3/maps-download", this->quest_category_index, true);
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(),
|
||||||
|
new_default_quest_index = std::move(new_default_quest_index),
|
||||||
|
new_ep3_download_quest_index = std::move(new_ep3_download_quest_index)]() {
|
||||||
|
s->default_quest_index = std::move(new_default_quest_index);
|
||||||
|
s->ep3_download_quest_index = std::move(new_ep3_download_quest_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::compile_functions() {
|
void ServerState::compile_functions(bool from_non_event_thread) {
|
||||||
config_log.info("Compiling client functions");
|
config_log.info("Compiling client functions");
|
||||||
this->function_code_index = make_shared<FunctionCodeIndex>("system/client-functions");
|
auto new_function_code_index = make_shared<FunctionCodeIndex>("system/client-functions");
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_function_code_index = std::move(new_function_code_index)]() {
|
||||||
|
s->function_code_index = std::move(new_function_code_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_dol_files() {
|
void ServerState::load_dol_files(bool from_non_event_thread) {
|
||||||
config_log.info("Loading DOL files");
|
config_log.info("Loading DOL files");
|
||||||
this->dol_file_index = make_shared<DOLFileIndex>("system/dol");
|
auto new_dol_file_index = make_shared<DOLFileIndex>("system/dol");
|
||||||
|
|
||||||
|
auto set = [s = this->shared_from_this(), new_dol_file_index = std::move(new_dol_file_index)]() {
|
||||||
|
s->dol_file_index = std::move(new_dol_file_index);
|
||||||
|
};
|
||||||
|
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::create_default_lobbies() {
|
void ServerState::create_default_lobbies() {
|
||||||
@@ -1537,86 +1655,27 @@ void ServerState::create_default_lobbies() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::create_load_step_graph() {
|
void ServerState::load_all() {
|
||||||
this->load_step_graph.add_step("all", {}, nullptr);
|
this->collect_network_addresses();
|
||||||
|
this->load_bb_private_keys(false);
|
||||||
// In: none
|
this->load_licenses(false);
|
||||||
// Out: all_addresses
|
this->clear_map_file_caches();
|
||||||
this->load_step_graph.add_step("network_addresses", {"all"}, bind(&ServerState::collect_network_addresses, this));
|
this->load_patch_indexes(false);
|
||||||
|
this->load_ep3_cards(false);
|
||||||
// In: none
|
this->load_ep3_maps(false);
|
||||||
// Out: bb_private_keys
|
this->load_ep3_tournament_state(false);
|
||||||
this->load_step_graph.add_step("bb_private_keys", {"all"}, bind(&ServerState::load_bb_private_keys, this));
|
this->compile_functions(false);
|
||||||
|
this->load_dol_files(false);
|
||||||
// In: none
|
this->create_default_lobbies();
|
||||||
// Out: license_index
|
this->load_set_data_tables(false);
|
||||||
this->load_step_graph.add_step("licenses", {"all"}, bind(&ServerState::load_licenses, this));
|
this->load_battle_params(false);
|
||||||
|
this->load_level_table(false);
|
||||||
// In: none
|
this->load_text_index(false);
|
||||||
// Out: map_file_caches
|
this->load_word_select_table(false);
|
||||||
this->load_step_graph.add_step("map_file_caches", {"all"}, bind(&ServerState::clear_map_file_caches, this));
|
this->load_item_definitions(false);
|
||||||
|
this->load_item_name_indexes(false);
|
||||||
// In: none
|
this->load_drop_tables(false);
|
||||||
// Out: pc_patch_file_index, bb_patch_file_index, bb_data_gsl
|
this->load_config();
|
||||||
this->load_step_graph.add_step("patch_indexes", {"all", "map_file_caches"}, bind(&ServerState::load_patch_indexes, this));
|
this->load_teams(false);
|
||||||
|
this->load_quest_index(false);
|
||||||
// In: none
|
|
||||||
// Out: ep3_map_index, ep3_card_index, ep3_card_index_trial, ep3_com_deck_index, ep3_tournament_index
|
|
||||||
this->load_step_graph.add_step("ep3_data", {"all"}, bind(&ServerState::load_ep3_data, this));
|
|
||||||
|
|
||||||
// In: none
|
|
||||||
// Out: function_code_index
|
|
||||||
this->load_step_graph.add_step("functions", {"all"}, bind(&ServerState::compile_functions, this));
|
|
||||||
|
|
||||||
// In: none
|
|
||||||
// Out: dol_file_index
|
|
||||||
this->load_step_graph.add_step("dol_files", {"all"}, bind(&ServerState::load_dol_files, this));
|
|
||||||
|
|
||||||
// In: none
|
|
||||||
// Out: lobbies
|
|
||||||
this->load_step_graph.add_step("lobbies", {"all"}, bind(&ServerState::create_default_lobbies, this));
|
|
||||||
|
|
||||||
// In: bb_patch_file_index
|
|
||||||
// Out: set_data_tables
|
|
||||||
this->load_step_graph.add_step("set_data_tables", {"all", "patch_indexes"}, bind(&ServerState::load_set_data_tables, this));
|
|
||||||
|
|
||||||
// In: bb_patch_file_index
|
|
||||||
// Out: battle_params
|
|
||||||
this->load_step_graph.add_step("battle_params", {"all", "patch_indexes"}, bind(&ServerState::load_battle_params, this));
|
|
||||||
|
|
||||||
// In: bb_patch_file_index
|
|
||||||
// Out: level_table
|
|
||||||
this->load_step_graph.add_step("level_table", {"all", "patch_indexes"}, bind(&ServerState::load_level_table, this));
|
|
||||||
|
|
||||||
// In: bb_patch_file_index
|
|
||||||
// Out: text_index
|
|
||||||
this->load_step_graph.add_step("text_index", {"all", "patch_indexes"}, bind(&ServerState::load_text_index, this));
|
|
||||||
|
|
||||||
// In: text_index (optional)
|
|
||||||
// Out: word_select_table
|
|
||||||
this->load_step_graph.add_step("word_select_table", {"all"}, bind(&ServerState::load_word_select_table, this));
|
|
||||||
|
|
||||||
// In: none
|
|
||||||
// Out: item_parameter_tables, mag_evolution_table
|
|
||||||
this->load_step_graph.add_step("item_definitions", {"all"}, bind(&ServerState::load_item_definitions, this));
|
|
||||||
|
|
||||||
// In: text_index, item_parameter_tables
|
|
||||||
// Out: item_name_indexes
|
|
||||||
this->load_step_graph.add_step("item_name_indexes", {"all", "text_index", "item_definitions"}, bind(&ServerState::load_item_name_indexes, this));
|
|
||||||
|
|
||||||
// In: none
|
|
||||||
// Out: rare_item_sets, common_item_sets, armor_random_set, tool_random_set, weapon_random_sets, tekker_adjustment_set
|
|
||||||
this->load_step_graph.add_step("drop_tables", {"all", "item_definitions", "item_name_indexes"}, bind(&ServerState::load_drop_tables, this));
|
|
||||||
|
|
||||||
// In: all_addresses, ep3_card_index, item_name_indexes
|
|
||||||
// Out: config, ep3_lobby_banners, quest_category_index, information menus, proxy destinations menus, team_reward_defs_json
|
|
||||||
this->load_step_graph.add_step("config", {"all", "network_addresses", "ep3_data", "item_name_indexes"}, bind(&ServerState::load_config, this));
|
|
||||||
|
|
||||||
// In: team_reward_defs_json
|
|
||||||
// Out: team_index
|
|
||||||
this->load_step_graph.add_step("teams", {"all", "config"}, bind(&ServerState::load_teams, this));
|
|
||||||
|
|
||||||
// In: quest_category_index
|
|
||||||
// Out: default_quest_index, ep3_download_quest_index
|
|
||||||
this->load_step_graph.add_step("quest_index", {"all", "config"}, bind(&ServerState::load_quest_index, this));
|
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-25
@@ -15,6 +15,7 @@
|
|||||||
#include "CommonItemSet.hh"
|
#include "CommonItemSet.hh"
|
||||||
#include "Episode3/DataIndexes.hh"
|
#include "Episode3/DataIndexes.hh"
|
||||||
#include "Episode3/Tournament.hh"
|
#include "Episode3/Tournament.hh"
|
||||||
|
#include "EventUtils.hh"
|
||||||
#include "FunctionCompiler.hh"
|
#include "FunctionCompiler.hh"
|
||||||
#include "GSLArchive.hh"
|
#include "GSLArchive.hh"
|
||||||
#include "ItemNameIndex.hh"
|
#include "ItemNameIndex.hh"
|
||||||
@@ -25,7 +26,6 @@
|
|||||||
#include "Menu.hh"
|
#include "Menu.hh"
|
||||||
#include "PlayerFilesManager.hh"
|
#include "PlayerFilesManager.hh"
|
||||||
#include "Quest.hh"
|
#include "Quest.hh"
|
||||||
#include "StepGraph.hh"
|
|
||||||
#include "TeamIndex.hh"
|
#include "TeamIndex.hh"
|
||||||
#include "WordSelectTable.hh"
|
#include "WordSelectTable.hh"
|
||||||
|
|
||||||
@@ -69,8 +69,6 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
bool config_loaded = false;
|
bool config_loaded = false;
|
||||||
bool default_lobbies_created = false;
|
bool default_lobbies_created = false;
|
||||||
|
|
||||||
StepGraph load_step_graph;
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::unordered_map<std::string, std::shared_ptr<PortConfiguration>> name_to_port_config;
|
std::unordered_map<std::string, std::shared_ptr<PortConfiguration>> name_to_port_config;
|
||||||
std::unordered_map<uint16_t, std::shared_ptr<PortConfiguration>> number_to_port_config;
|
std::unordered_map<uint16_t, std::shared_ptr<PortConfiguration>> number_to_port_config;
|
||||||
@@ -245,11 +243,6 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
ServerState& operator=(const ServerState&) = delete;
|
ServerState& operator=(const ServerState&) = delete;
|
||||||
ServerState& operator=(ServerState&&) = delete;
|
ServerState& operator=(ServerState&&) = delete;
|
||||||
|
|
||||||
void load_objects_and_downstream_dependents(const std::string& what);
|
|
||||||
void load_objects_and_downstream_dependents(const std::vector<std::string>& what);
|
|
||||||
void load_objects_and_upstream_dependents(const std::string& what);
|
|
||||||
void load_objects_and_upstream_dependents(const std::vector<std::string>& what);
|
|
||||||
|
|
||||||
void add_client_to_available_lobby(std::shared_ptr<Client> c);
|
void add_client_to_available_lobby(std::shared_ptr<Client> c);
|
||||||
void remove_client_from_lobby(std::shared_ptr<Client> c);
|
void remove_client_from_lobby(std::shared_ptr<Client> c);
|
||||||
bool change_client_lobby(
|
bool change_client_lobby(
|
||||||
@@ -308,29 +301,45 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
std::pair<std::string, uint16_t> parse_port_spec(const JSON& json) const;
|
std::pair<std::string, uint16_t> parse_port_spec(const JSON& json) const;
|
||||||
std::vector<PortConfiguration> parse_port_configuration(const JSON& json) const;
|
std::vector<PortConfiguration> parse_port_configuration(const JSON& json) const;
|
||||||
|
|
||||||
void create_load_step_graph();
|
inline void forward_to_event_thread(std::function<void()>&& fn) {
|
||||||
|
::forward_to_event_thread(this->base, std::move(fn));
|
||||||
|
}
|
||||||
|
inline void forward_or_call(bool from_non_event_thread, std::function<void()>&& fn) {
|
||||||
|
if (from_non_event_thread) {
|
||||||
|
::forward_to_event_thread(this->base, std::move(fn));
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following functions may only be called from a non-event thread if they
|
||||||
|
// take a from_non_event_thread argument; any function that does not have this
|
||||||
|
// argument must be called only from the event thread.
|
||||||
void create_default_lobbies();
|
void create_default_lobbies();
|
||||||
void collect_network_addresses();
|
void collect_network_addresses();
|
||||||
void load_config();
|
void load_config();
|
||||||
void load_bb_private_keys();
|
void load_bb_private_keys(bool from_non_event_thread);
|
||||||
void load_licenses();
|
void load_licenses(bool from_non_event_thread);
|
||||||
void load_teams();
|
void load_teams(bool from_non_event_thread);
|
||||||
void load_patch_indexes();
|
void load_patch_indexes(bool from_non_event_thread);
|
||||||
void clear_map_file_caches();
|
void clear_map_file_caches();
|
||||||
void load_battle_params();
|
void load_battle_params(bool from_non_event_thread);
|
||||||
void load_level_table();
|
void load_level_table(bool from_non_event_thread);
|
||||||
void load_text_index();
|
void load_text_index(bool from_non_event_thread);
|
||||||
static std::shared_ptr<ItemNameIndex> create_item_name_index_for_version(
|
static std::shared_ptr<ItemNameIndex> create_item_name_index_for_version(
|
||||||
Version version, std::shared_ptr<const ItemParameterTable> pmt, std::shared_ptr<const TextIndex> text_index);
|
Version version, std::shared_ptr<const ItemParameterTable> pmt, std::shared_ptr<const TextIndex> text_index);
|
||||||
void load_item_name_indexes();
|
void load_item_name_indexes(bool from_non_event_thread);
|
||||||
void load_drop_tables();
|
void load_drop_tables(bool from_non_event_thread);
|
||||||
void load_item_definitions();
|
void load_item_definitions(bool from_non_event_thread);
|
||||||
void load_set_data_tables();
|
void load_set_data_tables(bool from_non_event_thread);
|
||||||
void load_word_select_table();
|
void load_word_select_table(bool from_non_event_thread);
|
||||||
void load_ep3_data();
|
void load_ep3_cards(bool from_non_event_thread);
|
||||||
void load_quest_index();
|
void load_ep3_maps(bool from_non_event_thread);
|
||||||
void compile_functions();
|
void load_ep3_tournament_state(bool from_non_event_thread);
|
||||||
void load_dol_files();
|
void load_quest_index(bool from_non_event_thread);
|
||||||
|
void compile_functions(bool from_non_event_thread);
|
||||||
|
void load_dol_files(bool from_non_event_thread);
|
||||||
|
void load_all();
|
||||||
|
|
||||||
void enqueue_destroy_lobbies();
|
void enqueue_destroy_lobbies();
|
||||||
static void dispatch_destroy_lobbies(evutil_socket_t, short, void* ctx);
|
static void dispatch_destroy_lobbies(evutil_socket_t, short, void* ctx);
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
#include "Shell.hh"
|
|
||||||
|
|
||||||
#include <event2/event.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <phosg/Strings.hh>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const std::string Shell::PROMPT("newserv> ");
|
|
||||||
|
|
||||||
Shell::exit_shell::exit_shell() : runtime_error("shell exited") {}
|
|
||||||
|
|
||||||
Shell::Shell(std::shared_ptr<struct event_base> base)
|
|
||||||
: base(base),
|
|
||||||
read_event(
|
|
||||||
event_new(this->base.get(), 0, EV_READ | EV_PERSIST, &Shell::dispatch_read_stdin, this),
|
|
||||||
event_free),
|
|
||||||
prompt_event(
|
|
||||||
event_new(this->base.get(), 0, EV_TIMEOUT, &Shell::dispatch_print_prompt, this),
|
|
||||||
event_free) {
|
|
||||||
event_add(this->read_event.get(), nullptr);
|
|
||||||
|
|
||||||
// Schedule an event to print the prompt as soon as the event loop starts
|
|
||||||
// running. We do this so the prompt appears after any initialization
|
|
||||||
// messages that come after starting the shell
|
|
||||||
struct timeval tv = {0, 0};
|
|
||||||
event_add(this->prompt_event.get(), &tv);
|
|
||||||
|
|
||||||
this->poll.add(0, POLLIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shell::dispatch_print_prompt(evutil_socket_t, short, void* ctx) {
|
|
||||||
reinterpret_cast<Shell*>(ctx)->print_prompt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shell::print_prompt() {
|
|
||||||
// Default behavior: no prompt
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shell::dispatch_read_stdin(evutil_socket_t, short, void* ctx) {
|
|
||||||
reinterpret_cast<Shell*>(ctx)->read_stdin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shell::read_stdin() {
|
|
||||||
bool any_command_read = false;
|
|
||||||
for (;;) {
|
|
||||||
auto poll_result = this->poll.poll();
|
|
||||||
short fd_events = 0;
|
|
||||||
try {
|
|
||||||
fd_events = poll_result.at(0);
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fd_events & POLLIN)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string command(2048, '\0');
|
|
||||||
if (!fgets(command.data(), command.size(), stdin)) {
|
|
||||||
if (!any_command_read) {
|
|
||||||
// ctrl+d probably; we should exit
|
|
||||||
fputc('\n', stderr);
|
|
||||||
event_base_loopexit(this->base.get(), nullptr);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
break; // probably not EOF; just no more commands for now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim the extra data off the string
|
|
||||||
size_t len = strlen(command.c_str());
|
|
||||||
if (len == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (command[len - 1] == '\n') {
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
command.resize(len);
|
|
||||||
any_command_read = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
execute_command(command);
|
|
||||||
} catch (const exit_shell&) {
|
|
||||||
event_base_loopexit(this->base.get(), nullptr);
|
|
||||||
return;
|
|
||||||
} catch (const exception& e) {
|
|
||||||
fprintf(stderr, "FAILED: %s\n", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->print_prompt();
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <event2/event.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <phosg/Filesystem.hh>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "ServerState.hh"
|
|
||||||
|
|
||||||
class Shell {
|
|
||||||
public:
|
|
||||||
Shell(std::shared_ptr<struct event_base> base);
|
|
||||||
virtual ~Shell() = default;
|
|
||||||
Shell(const Shell&) = delete;
|
|
||||||
Shell(Shell&&) = delete;
|
|
||||||
Shell& operator=(const Shell&) = delete;
|
|
||||||
Shell& operator=(Shell&&) = delete;
|
|
||||||
|
|
||||||
static const std::string PROMPT;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<struct event_base> base;
|
|
||||||
std::unique_ptr<struct event, void (*)(struct event*)> read_event;
|
|
||||||
std::unique_ptr<struct event, void (*)(struct event*)> prompt_event;
|
|
||||||
Poll poll;
|
|
||||||
|
|
||||||
class exit_shell : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
exit_shell();
|
|
||||||
~exit_shell() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dispatch_print_prompt(evutil_socket_t fd, short events, void* ctx);
|
|
||||||
static void dispatch_read_stdin(evutil_socket_t fd, short events, void* ctx);
|
|
||||||
virtual void print_prompt();
|
|
||||||
void read_stdin();
|
|
||||||
virtual void execute_command(const std::string& command) = 0;
|
|
||||||
};
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#include "StepGraph.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void StepGraph::add_step(const string& name, const vector<string>& depends_on_names, function<void()>&& execute) {
|
|
||||||
auto new_step = make_shared<Step>();
|
|
||||||
new_step->execute = std::move(execute);
|
|
||||||
this->steps.emplace(name, new_step);
|
|
||||||
|
|
||||||
for (const auto& depends_on_name : depends_on_names) {
|
|
||||||
auto upstream_step = this->steps.at(depends_on_name);
|
|
||||||
upstream_step->downstream_dependencies.emplace_back(new_step);
|
|
||||||
new_step->upstream_dependencies.emplace_back(upstream_step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StepGraph::run(const string& start_step_name, bool run_upstreams) {
|
|
||||||
vector<string> start_step_names({start_step_name});
|
|
||||||
this->run(start_step_names, run_upstreams);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StepGraph::run(const vector<string>& start_step_names, bool run_upstreams) {
|
|
||||||
// Collect all steps to run
|
|
||||||
deque<shared_ptr<Step>> steps_to_visit;
|
|
||||||
try {
|
|
||||||
for (const auto& start_step_name : start_step_names) {
|
|
||||||
steps_to_visit.emplace_back(this->steps.at(start_step_name));
|
|
||||||
}
|
|
||||||
} catch (const out_of_range&) {
|
|
||||||
throw runtime_error("invalid step name");
|
|
||||||
}
|
|
||||||
unordered_set<shared_ptr<Step>> steps_to_run;
|
|
||||||
while (!steps_to_visit.empty()) {
|
|
||||||
auto step = std::move(steps_to_visit.front());
|
|
||||||
steps_to_visit.pop_front();
|
|
||||||
if (steps_to_run.emplace(step).second) {
|
|
||||||
if (run_upstreams) {
|
|
||||||
for (const auto& w_other_step : step->upstream_dependencies) {
|
|
||||||
auto other_step = w_other_step.lock();
|
|
||||||
if (!other_step) {
|
|
||||||
throw runtime_error("upstream step is deleted");
|
|
||||||
}
|
|
||||||
steps_to_visit.emplace_back(other_step);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const auto& other_step : step->downstream_dependencies) {
|
|
||||||
steps_to_visit.emplace_back(other_step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Topological sort: repeatedly take all steps that are not a downstream
|
|
||||||
// dependency of any other step in the set
|
|
||||||
vector<shared_ptr<Step>> steps_order;
|
|
||||||
steps_order.reserve(steps_to_run.size());
|
|
||||||
while (!steps_to_run.empty()) {
|
|
||||||
unordered_set<shared_ptr<Step>> candidate_steps = steps_to_run;
|
|
||||||
for (const auto& step : steps_to_run) {
|
|
||||||
for (const auto& downstream_step : step->downstream_dependencies) {
|
|
||||||
candidate_steps.erase(downstream_step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (candidate_steps.empty()) {
|
|
||||||
throw logic_error("dependency graph contains a cycle");
|
|
||||||
}
|
|
||||||
for (const auto& step : candidate_steps) {
|
|
||||||
steps_to_run.erase(step);
|
|
||||||
steps_order.emplace_back(step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the steps in order
|
|
||||||
uint64_t run_id = ++this->last_run_id;
|
|
||||||
for (auto step : steps_order) {
|
|
||||||
if (step->last_run_id < run_id) {
|
|
||||||
step->last_run_id = run_id;
|
|
||||||
if (step->execute) {
|
|
||||||
step->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <phosg/Strings.hh>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct StepGraph {
|
|
||||||
struct Step {
|
|
||||||
std::vector<std::shared_ptr<Step>> downstream_dependencies;
|
|
||||||
std::vector<std::weak_ptr<Step>> upstream_dependencies;
|
|
||||||
std::function<void()> execute;
|
|
||||||
uint64_t last_run_id = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<Step>> steps;
|
|
||||||
uint64_t last_run_id = 0;
|
|
||||||
|
|
||||||
StepGraph() = default;
|
|
||||||
|
|
||||||
void add_step(const std::string& name, const std::vector<std::string>& depends_on_names, std::function<void()>&& execute);
|
|
||||||
void run(const std::string& start_step, bool run_upstreams);
|
|
||||||
void run(const std::vector<std::string>& start_steps, bool run_upstreams);
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user