support per-quest common and rare tables
This commit is contained in:
@@ -23,6 +23,10 @@ public:
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
inline size_t num_entries() const {
|
||||
return this->entries.size();
|
||||
}
|
||||
|
||||
std::pair<const void*, size_t> get(size_t index) const;
|
||||
std::string get_copy(size_t index) const;
|
||||
phosg::StringReader get_reader(size_t index) const;
|
||||
|
||||
+32
-33
@@ -785,41 +785,40 @@ ChatCommandDefinition cc_dropmode(
|
||||
|
||||
if (a.c->proxy_session) {
|
||||
|
||||
using DropMode = ProxySession::DropMode;
|
||||
if (a.text.empty()) {
|
||||
switch (a.c->proxy_session->drop_mode) {
|
||||
case DropMode::DISABLED:
|
||||
case ProxyDropMode::DISABLED:
|
||||
send_text_message(a.c, "Drop mode: disabled");
|
||||
break;
|
||||
case DropMode::PASSTHROUGH:
|
||||
case ProxyDropMode::PASSTHROUGH:
|
||||
send_text_message(a.c, "Drop mode: default");
|
||||
break;
|
||||
case DropMode::INTERCEPT:
|
||||
case ProxyDropMode::INTERCEPT:
|
||||
send_text_message(a.c, "Drop mode: proxy");
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
DropMode new_mode;
|
||||
ProxyDropMode new_mode;
|
||||
if ((a.text == "none") || (a.text == "disabled")) {
|
||||
new_mode = DropMode::DISABLED;
|
||||
new_mode = ProxyDropMode::DISABLED;
|
||||
} else if ((a.text == "default") || (a.text == "passthrough")) {
|
||||
new_mode = DropMode::PASSTHROUGH;
|
||||
new_mode = ProxyDropMode::PASSTHROUGH;
|
||||
} else if ((a.text == "proxy") || (a.text == "intercept")) {
|
||||
new_mode = DropMode::INTERCEPT;
|
||||
new_mode = ProxyDropMode::INTERCEPT;
|
||||
} else {
|
||||
throw precondition_failed("Invalid drop mode");
|
||||
}
|
||||
|
||||
a.c->proxy_session->set_drop_mode(s, a.c->version(), a.c->override_random_seed, new_mode);
|
||||
switch (a.c->proxy_session->drop_mode) {
|
||||
case DropMode::DISABLED:
|
||||
case ProxyDropMode::DISABLED:
|
||||
send_text_message(a.c->channel, "Item drops disabled");
|
||||
break;
|
||||
case DropMode::PASSTHROUGH:
|
||||
case ProxyDropMode::PASSTHROUGH:
|
||||
send_text_message(a.c->channel, "Item drops changed\nto default mode");
|
||||
break;
|
||||
case DropMode::INTERCEPT:
|
||||
case ProxyDropMode::INTERCEPT:
|
||||
send_text_message(a.c->channel, "Item drops changed\nto proxy mode");
|
||||
break;
|
||||
}
|
||||
@@ -829,36 +828,36 @@ ChatCommandDefinition cc_dropmode(
|
||||
auto l = a.c->require_lobby();
|
||||
if (a.text.empty()) {
|
||||
switch (l->drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
send_text_message(a.c, "Drop mode: disabled");
|
||||
break;
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::CLIENT:
|
||||
send_text_message(a.c, "Drop mode: client");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
send_text_message(a.c, "Drop mode: server\nshared");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
send_text_message(a.c, "Drop mode: server\nprivate");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
send_text_message(a.c, "Drop mode: server\nduplicate");
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
a.check_is_leader();
|
||||
Lobby::DropMode new_mode;
|
||||
ServerDropMode new_mode;
|
||||
if ((a.text == "none") || (a.text == "disabled")) {
|
||||
new_mode = Lobby::DropMode::DISABLED;
|
||||
new_mode = ServerDropMode::DISABLED;
|
||||
} else if (a.text == "client") {
|
||||
new_mode = Lobby::DropMode::CLIENT;
|
||||
new_mode = ServerDropMode::CLIENT;
|
||||
} else if ((a.text == "shared") || (a.text == "server")) {
|
||||
new_mode = Lobby::DropMode::SERVER_SHARED;
|
||||
new_mode = ServerDropMode::SERVER_SHARED;
|
||||
} else if ((a.text == "private") || (a.text == "priv")) {
|
||||
new_mode = Lobby::DropMode::SERVER_PRIVATE;
|
||||
new_mode = ServerDropMode::SERVER_PRIVATE;
|
||||
} else if ((a.text == "duplicate") || (a.text == "dup")) {
|
||||
new_mode = Lobby::DropMode::SERVER_DUPLICATE;
|
||||
new_mode = ServerDropMode::SERVER_DUPLICATE;
|
||||
} else {
|
||||
throw precondition_failed("Invalid drop mode");
|
||||
}
|
||||
@@ -869,19 +868,19 @@ ChatCommandDefinition cc_dropmode(
|
||||
|
||||
l->drop_mode = new_mode;
|
||||
switch (l->drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
send_text_message(l, "Item drops disabled");
|
||||
break;
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::CLIENT:
|
||||
send_text_message(l, "Item drops changed\nto client mode");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
send_text_message(l, "Item drops changed\nto server shared\nmode");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
send_text_message(l, "Item drops changed\nto server private\nmode");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
send_text_message(l, "Item drops changed\nto server duplicate\nmode");
|
||||
break;
|
||||
}
|
||||
@@ -1262,7 +1261,7 @@ ChatCommandDefinition cc_item(
|
||||
item = s->parse_item_description(a.c->version(), a.text);
|
||||
item.id = l->generate_item_id(a.c->lobby_client_id);
|
||||
|
||||
if ((l->drop_mode == Lobby::DropMode::SERVER_PRIVATE) || (l->drop_mode == Lobby::DropMode::SERVER_DUPLICATE)) {
|
||||
if ((l->drop_mode == ServerDropMode::SERVER_PRIVATE) || (l->drop_mode == ServerDropMode::SERVER_DUPLICATE)) {
|
||||
l->add_item(a.c->floor, item, a.c->pos, nullptr, nullptr, (1 << a.c->lobby_client_id));
|
||||
send_drop_stacked_item_to_channel(s, a.c->channel, item, a.c->floor, a.c->pos);
|
||||
} else {
|
||||
@@ -1452,19 +1451,19 @@ ChatCommandDefinition cc_lobby_info(
|
||||
"$C7Section ID: $C6{}$C7", name_for_section_id(l->effective_section_id())));
|
||||
|
||||
switch (l->drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
lines.emplace_back("Drops disabled");
|
||||
break;
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::CLIENT:
|
||||
lines.emplace_back("Client item table");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
lines.emplace_back("Server item table");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
lines.emplace_back("Server indiv items");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
lines.emplace_back("Server dup items");
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -435,9 +435,9 @@ struct C_LegacyLogin_BB_04 {
|
||||
// 05 = Server down for maintenance (108)
|
||||
// 06 = Incorrect password (127)
|
||||
// Any other nonzero value = Generic failure (101)
|
||||
// The client config field in this command is ignored by pre-V3 clients as well
|
||||
// as Episodes 1&2 Trial Edition. All other V3 clients save it as opaque data to
|
||||
// be returned in a 9E or 9F command later.
|
||||
// The client config field in this command is ignored by all clients that never
|
||||
// send 9E. Clients that do send 9E will save thie client config as opaque data
|
||||
// to be returned in a 9E or 9F command later.
|
||||
// The client will respond with a 96 command, but only the first time it
|
||||
// receives this command - for later 04 commands, the client will still update
|
||||
// its client config but will not respond. Changing the security data at any
|
||||
@@ -4298,7 +4298,8 @@ struct G_FeedMag_6x28 {
|
||||
le_uint32_t fed_item_id = 0;
|
||||
} __packed_ws__(G_FeedMag_6x28, 0x0C);
|
||||
|
||||
// 6x29: Delete inventory item (via bank deposit / sale / feeding MAG) (protected on V3 but not V4)
|
||||
// 6x29: Delete inventory item (via bank deposit / sale / feeding MAG)
|
||||
// (protected on V3 but not on V4)
|
||||
// This subcommand is also used for reducing the size of stacks - if amount is
|
||||
// less than the stack count, the item is not deleted and its ID remains valid.
|
||||
|
||||
@@ -5739,14 +5740,16 @@ struct G_SetLobbyChairState_6xAE {
|
||||
le_float unknown_a4 = 0;
|
||||
} __packed_ws__(G_SetLobbyChairState_6xAE, 0x10);
|
||||
|
||||
// 6xAF: Turn lobby chair (not valid on pre-V3 or GC Trial Edition) (protected on V3/V4)
|
||||
// 6xAF: Turn lobby chair (not valid on pre-V3 or GC Trial Edition) (protected
|
||||
// on V3/V4)
|
||||
|
||||
struct G_TurnLobbyChair_6xAF {
|
||||
G_ClientIDHeader header;
|
||||
le_uint32_t angle = 0; // In range [0x0000, 0xFFFF]
|
||||
} __packed_ws__(G_TurnLobbyChair_6xAF, 8);
|
||||
|
||||
// 6xB0: Move lobby chair (not valid on pre-V3 or GC Trial Edition) (protected on V3/V4)
|
||||
// 6xB0: Move lobby chair (not valid on pre-V3 or GC Trial Edition) (protected
|
||||
// on V3/V4)
|
||||
|
||||
struct G_MoveLobbyChair_6xB0 {
|
||||
G_ClientIDHeader header;
|
||||
|
||||
+48
-24
@@ -677,29 +677,49 @@ shared_ptr<const CommonItemSet::Table> CommonItemSet::get_table(
|
||||
}
|
||||
|
||||
AFSV2CommonItemSet::AFSV2CommonItemSet(
|
||||
std::shared_ptr<const std::string> pt_afs_data,
|
||||
std::shared_ptr<const std::string> ct_afs_data) {
|
||||
// ItemPT.afs has 40 entries; the first 10 are for Normal, then Hard, etc.
|
||||
AFSArchive pt_afs(pt_afs_data);
|
||||
for (size_t difficulty = 0; difficulty < 4; difficulty++) {
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
auto entry = pt_afs.get(difficulty * 10 + section_id);
|
||||
phosg::StringReader r(entry.first, entry.second);
|
||||
auto table = make_shared<Table>(r, false, false, Episode::EP1);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::NORMAL, difficulty, section_id), table);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::BATTLE, difficulty, section_id), table);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::SOLO, difficulty, section_id), table);
|
||||
std::shared_ptr<const std::string> pt_afs_data, std::shared_ptr<const std::string> ct_afs_data) {
|
||||
// Each AFS file has 40 entries (30 on v1); the first 10 are for Normal, then
|
||||
// Hard, etc.
|
||||
{
|
||||
AFSArchive pt_afs(pt_afs_data);
|
||||
size_t max_difficulty;
|
||||
if (pt_afs.num_entries() >= 40) {
|
||||
max_difficulty = 4;
|
||||
} else if (pt_afs.num_entries() >= 30) {
|
||||
max_difficulty = 3;
|
||||
} else {
|
||||
throw std::runtime_error(std::format("PT AFS file has unexpected entry count ({})", pt_afs.num_entries()));
|
||||
}
|
||||
for (size_t difficulty = 0; difficulty < max_difficulty; difficulty++) {
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
auto entry = pt_afs.get(difficulty * 10 + section_id);
|
||||
phosg::StringReader r(entry.first, entry.second);
|
||||
auto table = make_shared<Table>(r, false, false, Episode::EP1);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::NORMAL, difficulty, section_id), table);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::BATTLE, difficulty, section_id), table);
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::SOLO, difficulty, section_id), table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ItemCT.afs also has 40 entries, but only the 0th, 10th, 20th, and 30th are
|
||||
// used (section_id is ignored)
|
||||
AFSArchive ct_afs(ct_afs_data);
|
||||
for (size_t difficulty = 0; difficulty < 4; difficulty++) {
|
||||
auto r = ct_afs.get_reader(difficulty * 10);
|
||||
auto table = make_shared<Table>(r, false, false, Episode::EP1);
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::CHALLENGE, difficulty, section_id), table);
|
||||
// ItemCT AFS files also have 40 entries, but only the 0th, 10th, 20th, and
|
||||
// 30th are used (section_id is ignored)
|
||||
if (ct_afs_data) {
|
||||
AFSArchive ct_afs(ct_afs_data);
|
||||
size_t max_difficulty;
|
||||
if (ct_afs.num_entries() >= 40) {
|
||||
max_difficulty = 4;
|
||||
} else if (ct_afs.num_entries() >= 30) {
|
||||
max_difficulty = 3;
|
||||
} else {
|
||||
throw std::runtime_error(std::format("CT AFS file has unexpected entry count ({})", ct_afs.num_entries()));
|
||||
}
|
||||
for (size_t difficulty = 0; difficulty < max_difficulty; difficulty++) {
|
||||
auto r = ct_afs.get_reader(difficulty * 10);
|
||||
auto table = make_shared<Table>(r, false, false, Episode::EP1);
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::CHALLENGE, difficulty, section_id), table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,10 +778,14 @@ GSLV3V4CommonItemSet::GSLV3V4CommonItemSet(std::shared_ptr<const std::string> gs
|
||||
|
||||
if (episode != Episode::EP4) {
|
||||
for (size_t difficulty = 0; difficulty < 4; difficulty++) {
|
||||
auto r = gsl.get_reader(filename_for_table(episode, difficulty, 0, true));
|
||||
auto table = make_shared<Table>(r, is_big_endian, true, episode);
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
this->tables.emplace(this->key_for_table(episode, GameMode::CHALLENGE, difficulty, section_id), table);
|
||||
try {
|
||||
auto r = gsl.get_reader(filename_for_table(episode, difficulty, 0, true));
|
||||
auto table = make_shared<Table>(r, is_big_endian, true, episode);
|
||||
for (size_t section_id = 0; section_id < 10; section_id++) {
|
||||
this->tables.emplace(this->key_for_table(episode, GameMode::CHALLENGE, difficulty, section_id), table);
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
// GC NTE doesn't have Ep2 challenge; just skip adding the table
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-15
@@ -328,13 +328,13 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_client_json(
|
||||
{"LobbyPlayers", std::move(lobby_players_json)},
|
||||
});
|
||||
switch (ses->drop_mode) {
|
||||
case ProxySession::DropMode::DISABLED:
|
||||
case ProxyDropMode::DISABLED:
|
||||
ses_json.emplace("DropMode", "none");
|
||||
break;
|
||||
case ProxySession::DropMode::PASSTHROUGH:
|
||||
case ProxyDropMode::PASSTHROUGH:
|
||||
ses_json.emplace("DropMode", "default");
|
||||
break;
|
||||
case ProxySession::DropMode::INTERCEPT:
|
||||
case ProxyDropMode::INTERCEPT:
|
||||
ses_json.emplace("DropMode", "proxy");
|
||||
break;
|
||||
}
|
||||
@@ -386,19 +386,19 @@ std::shared_ptr<phosg::JSON> HTTPServer::generate_lobby_json(
|
||||
ret->emplace("EXPShareMultiplier", l->exp_share_multiplier);
|
||||
ret->emplace("AllowedDropModes", l->allowed_drop_modes);
|
||||
switch (l->drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
ret->emplace("DropMode", "none");
|
||||
break;
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::CLIENT:
|
||||
ret->emplace("DropMode", "client");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
ret->emplace("DropMode", "shared");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
ret->emplace("DropMode", "private");
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
ret->emplace("DropMode", "duplicate");
|
||||
break;
|
||||
}
|
||||
@@ -669,12 +669,23 @@ asio::awaitable<std::shared_ptr<phosg::JSON>> HTTPServer::generate_ep3_cards_jso
|
||||
});
|
||||
}
|
||||
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> HTTPServer::generate_common_tables_json() const {
|
||||
auto v2_table = this->state->common_item_set_v2;
|
||||
auto v3_v4_table = this->state->common_item_set_v3_v4;
|
||||
co_return co_await call_on_thread_pool(*this->state->thread_pool, [&]() -> shared_ptr<phosg::JSON> {
|
||||
return make_shared<phosg::JSON>(phosg::JSON::dict({{"v1_v2", v2_table->json()}, {"v3_v4", v3_v4_table->json()}}));
|
||||
});
|
||||
std::shared_ptr<phosg::JSON> HTTPServer::generate_common_table_list_json() const {
|
||||
auto ret = make_shared<phosg::JSON>(phosg::JSON::list());
|
||||
for (const auto& it : this->state->common_item_sets) {
|
||||
ret->emplace_back(it.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> HTTPServer::generate_common_table_json(const std::string& table_name) const {
|
||||
try {
|
||||
const auto& table = this->state->common_item_sets.at(table_name);
|
||||
co_return co_await call_on_thread_pool(*this->state->thread_pool, [&]() -> shared_ptr<phosg::JSON> {
|
||||
return make_shared<phosg::JSON>(table->json());
|
||||
});
|
||||
} catch (const out_of_range&) {
|
||||
throw HTTPError(404, "Table does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<phosg::JSON> HTTPServer::generate_rare_table_list_json() const {
|
||||
@@ -794,7 +805,10 @@ asio::awaitable<std::unique_ptr<HTTPResponse>> HTTPServer::handle_request(shared
|
||||
ret = co_await this->generate_ep3_cards_json(true);
|
||||
} else if (req.path == "/y/data/common-tables") {
|
||||
this->require_GET(req);
|
||||
ret = co_await this->generate_common_tables_json();
|
||||
ret = this->generate_common_table_list_json();
|
||||
} else if (req.path.starts_with("/y/data/common-tables/")) {
|
||||
this->require_GET(req);
|
||||
ret = co_await this->generate_common_table_json(req.path.substr(22));
|
||||
} else if (req.path == "/y/data/rare-tables") {
|
||||
this->require_GET(req);
|
||||
ret = this->generate_rare_table_list_json();
|
||||
|
||||
+2
-1
@@ -37,8 +37,9 @@ protected:
|
||||
std::shared_ptr<phosg::JSON> generate_all_json() const;
|
||||
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> generate_ep3_cards_json(bool trial) const;
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> generate_common_tables_json() const;
|
||||
std::shared_ptr<phosg::JSON> generate_common_table_list_json() const;
|
||||
std::shared_ptr<phosg::JSON> generate_rare_table_list_json() const;
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> generate_common_table_json(const std::string& table_name) const;
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> generate_rare_table_json(const std::string& table_name) const;
|
||||
asio::awaitable<std::shared_ptr<phosg::JSON>> generate_quest_list_json(std::shared_ptr<const QuestIndex> q);
|
||||
|
||||
|
||||
@@ -4,6 +4,41 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <>
|
||||
ServerDropMode phosg::enum_for_name<ServerDropMode>(const char* name) {
|
||||
if (!strcmp(name, "DISABLED")) {
|
||||
return ServerDropMode::DISABLED;
|
||||
} else if (!strcmp(name, "CLIENT")) {
|
||||
return ServerDropMode::CLIENT;
|
||||
} else if (!strcmp(name, "SERVER_SHARED")) {
|
||||
return ServerDropMode::SERVER_SHARED;
|
||||
} else if (!strcmp(name, "SERVER_PRIVATE")) {
|
||||
return ServerDropMode::SERVER_PRIVATE;
|
||||
} else if (!strcmp(name, "SERVER_DUPLICATE")) {
|
||||
return ServerDropMode::SERVER_DUPLICATE;
|
||||
} else {
|
||||
throw runtime_error("invalid drop mode");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* phosg::name_for_enum<ServerDropMode>(ServerDropMode value) {
|
||||
switch (value) {
|
||||
case ServerDropMode::DISABLED:
|
||||
return "DISABLED";
|
||||
case ServerDropMode::CLIENT:
|
||||
return "CLIENT";
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
return "SERVER_SHARED";
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
return "SERVER_PRIVATE";
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
return "SERVER_DUPLICATE";
|
||||
default:
|
||||
throw runtime_error("invalid drop mode");
|
||||
}
|
||||
}
|
||||
|
||||
ItemParameterTable::ItemParameterTable(shared_ptr<const string> data, Version version)
|
||||
: version(version),
|
||||
data(data),
|
||||
|
||||
@@ -16,6 +16,26 @@
|
||||
#include "Types.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
// TODO: These don't really belong here, but putting them anywhere else creates
|
||||
// annoying dependency cycles. Find or make a better place for these.
|
||||
enum class ServerDropMode {
|
||||
DISABLED = 0,
|
||||
CLIENT = 1, // Not allowed for BB games
|
||||
SERVER_SHARED = 2,
|
||||
SERVER_PRIVATE = 3,
|
||||
SERVER_DUPLICATE = 4,
|
||||
};
|
||||
enum class ProxyDropMode {
|
||||
DISABLED = 0,
|
||||
PASSTHROUGH,
|
||||
INTERCEPT,
|
||||
};
|
||||
|
||||
template <>
|
||||
ServerDropMode phosg::enum_for_name<ServerDropMode>(const char* name);
|
||||
template <>
|
||||
const char* phosg::name_for_enum<ServerDropMode>(ServerDropMode value);
|
||||
|
||||
class ItemParameterTable {
|
||||
public:
|
||||
// TODO: This implementation is ugly. We should use real classes and virtual
|
||||
|
||||
+3
-73
@@ -159,7 +159,7 @@ Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id, bool is_game)
|
||||
challenge_exp_multiplier(1.0f),
|
||||
random_seed(phosg::random_object<uint32_t>()),
|
||||
rand_crypt(make_shared<DisabledRandomGenerator>()),
|
||||
drop_mode(DropMode::CLIENT),
|
||||
drop_mode(ServerDropMode::CLIENT),
|
||||
event(0),
|
||||
block(0),
|
||||
leader_id(0),
|
||||
@@ -214,41 +214,6 @@ void Lobby::create_item_creator(Version logic_version) {
|
||||
logic_version = leader_c ? leader_c->version() : Version::BB_V4;
|
||||
}
|
||||
|
||||
shared_ptr<const RareItemSet> rare_item_set;
|
||||
shared_ptr<const CommonItemSet> common_item_set;
|
||||
switch (logic_version) {
|
||||
case Version::PC_PATCH:
|
||||
case Version::BB_PATCH:
|
||||
case Version::GC_EP3_NTE:
|
||||
case Version::GC_EP3:
|
||||
throw runtime_error("cannot create item creator for this base version");
|
||||
case Version::DC_NTE:
|
||||
case Version::DC_11_2000:
|
||||
case Version::DC_V1:
|
||||
// TODO: We should probably have a v1 common item set at some point too
|
||||
common_item_set = s->common_item_set_v2;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v1");
|
||||
break;
|
||||
case Version::DC_V2:
|
||||
case Version::PC_NTE:
|
||||
case Version::PC_V2:
|
||||
common_item_set = s->common_item_set_v2;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v2");
|
||||
break;
|
||||
case Version::GC_NTE:
|
||||
case Version::GC_V3:
|
||||
case Version::XB_V3:
|
||||
common_item_set = s->common_item_set_v3_v4;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v3");
|
||||
break;
|
||||
case Version::BB_V4:
|
||||
common_item_set = s->common_item_set_v3_v4;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v4");
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid lobby base version");
|
||||
}
|
||||
|
||||
shared_ptr<RandomGenerator> rand_crypt;
|
||||
if (s->use_psov2_rand_crypt) {
|
||||
rand_crypt = make_shared<PSOV2Encryption>(this->rand_crypt->seed());
|
||||
@@ -256,8 +221,8 @@ void Lobby::create_item_creator(Version logic_version) {
|
||||
rand_crypt = make_shared<MT19937Generator>(this->rand_crypt->seed());
|
||||
}
|
||||
this->item_creator = make_shared<ItemCreator>(
|
||||
common_item_set,
|
||||
rare_item_set,
|
||||
s->common_item_set(logic_version, this->quest),
|
||||
s->rare_item_set(logic_version, this->quest),
|
||||
s->armor_random_set,
|
||||
s->tool_random_set,
|
||||
s->weapon_random_sets.at(this->difficulty),
|
||||
@@ -884,38 +849,3 @@ bool Lobby::compare_shared(const shared_ptr<const Lobby>& a, const shared_ptr<co
|
||||
|
||||
return a->name < b->name;
|
||||
}
|
||||
|
||||
template <>
|
||||
Lobby::DropMode phosg::enum_for_name<Lobby::DropMode>(const char* name) {
|
||||
if (!strcmp(name, "DISABLED")) {
|
||||
return Lobby::DropMode::DISABLED;
|
||||
} else if (!strcmp(name, "CLIENT")) {
|
||||
return Lobby::DropMode::CLIENT;
|
||||
} else if (!strcmp(name, "SERVER_SHARED")) {
|
||||
return Lobby::DropMode::SERVER_SHARED;
|
||||
} else if (!strcmp(name, "SERVER_PRIVATE")) {
|
||||
return Lobby::DropMode::SERVER_PRIVATE;
|
||||
} else if (!strcmp(name, "SERVER_DUPLICATE")) {
|
||||
return Lobby::DropMode::SERVER_DUPLICATE;
|
||||
} else {
|
||||
throw runtime_error("invalid drop mode");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* phosg::name_for_enum<Lobby::DropMode>(Lobby::DropMode value) {
|
||||
switch (value) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
return "DISABLED";
|
||||
case Lobby::DropMode::CLIENT:
|
||||
return "CLIENT";
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
return "SERVER_SHARED";
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
return "SERVER_PRIVATE";
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
return "SERVER_DUPLICATE";
|
||||
default:
|
||||
throw runtime_error("invalid drop mode");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -90,13 +90,6 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
IS_OVERFLOW = 0x08000000,
|
||||
// clang-format on
|
||||
};
|
||||
enum class DropMode {
|
||||
DISABLED = 0,
|
||||
CLIENT = 1, // Not allowed for BB games
|
||||
SERVER_SHARED = 2,
|
||||
SERVER_PRIVATE = 3,
|
||||
SERVER_DUPLICATE = 4,
|
||||
};
|
||||
|
||||
std::weak_ptr<ServerState> server_state;
|
||||
phosg::PrefixedLogger log;
|
||||
@@ -136,7 +129,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
uint32_t random_seed;
|
||||
std::shared_ptr<RandomGenerator> rand_crypt;
|
||||
uint8_t allowed_drop_modes;
|
||||
DropMode drop_mode;
|
||||
ServerDropMode drop_mode;
|
||||
std::shared_ptr<ItemCreator> item_creator; // Always null for lobbies, never null for games
|
||||
|
||||
struct ChallengeParameters {
|
||||
@@ -291,6 +284,6 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
};
|
||||
|
||||
template <>
|
||||
Lobby::DropMode phosg::enum_for_name<Lobby::DropMode>(const char* name);
|
||||
ServerDropMode phosg::enum_for_name<ServerDropMode>(const char* name);
|
||||
template <>
|
||||
const char* phosg::name_for_enum<Lobby::DropMode>(Lobby::DropMode value);
|
||||
const char* phosg::name_for_enum<ServerDropMode>(ServerDropMode value);
|
||||
|
||||
@@ -844,13 +844,12 @@ static asio::awaitable<HandlerResult> SC_6x60_6xA2(shared_ptr<Client> c, Channel
|
||||
co_return HandlerResult::FORWARD;
|
||||
}
|
||||
|
||||
using DropMode = ProxySession::DropMode;
|
||||
switch (c->proxy_session->drop_mode) {
|
||||
case DropMode::DISABLED:
|
||||
case ProxyDropMode::DISABLED:
|
||||
co_return HandlerResult::SUPPRESS;
|
||||
case DropMode::PASSTHROUGH:
|
||||
case ProxyDropMode::PASSTHROUGH:
|
||||
co_return HandlerResult::FORWARD;
|
||||
case DropMode::INTERCEPT:
|
||||
case ProxyDropMode::INTERCEPT:
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid drop mode");
|
||||
|
||||
+5
-38
@@ -21,47 +21,14 @@ ProxySession::~ProxySession() {
|
||||
this->num_proxy_sessions--;
|
||||
}
|
||||
|
||||
void ProxySession::set_drop_mode(shared_ptr<ServerState> s, Version version, int64_t override_random_seed, DropMode new_mode) {
|
||||
void ProxySession::set_drop_mode(
|
||||
shared_ptr<ServerState> s, Version version, int64_t override_random_seed, ProxyDropMode new_mode) {
|
||||
this->drop_mode = new_mode;
|
||||
if (this->drop_mode == DropMode::INTERCEPT) {
|
||||
shared_ptr<const RareItemSet> rare_item_set;
|
||||
shared_ptr<const CommonItemSet> common_item_set;
|
||||
switch (version) {
|
||||
case Version::PC_PATCH:
|
||||
case Version::BB_PATCH:
|
||||
case Version::GC_EP3_NTE:
|
||||
case Version::GC_EP3:
|
||||
throw runtime_error("cannot create item creator for this base version");
|
||||
case Version::DC_NTE:
|
||||
case Version::DC_11_2000:
|
||||
case Version::DC_V1:
|
||||
// TODO: We should probably have a v1 common item set at some point too
|
||||
common_item_set = s->common_item_set_v2;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v1");
|
||||
break;
|
||||
case Version::DC_V2:
|
||||
case Version::PC_NTE:
|
||||
case Version::PC_V2:
|
||||
common_item_set = s->common_item_set_v2;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v2");
|
||||
break;
|
||||
case Version::GC_NTE:
|
||||
case Version::GC_V3:
|
||||
case Version::XB_V3:
|
||||
common_item_set = s->common_item_set_v3_v4;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v3");
|
||||
break;
|
||||
case Version::BB_V4:
|
||||
common_item_set = s->common_item_set_v3_v4;
|
||||
rare_item_set = s->rare_item_sets.at("rare-table-v4");
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid lobby base version");
|
||||
}
|
||||
if (this->drop_mode == ProxyDropMode::INTERCEPT) {
|
||||
auto rand_crypt = make_shared<MT19937Generator>((override_random_seed >= 0) ? override_random_seed : this->lobby_random_seed);
|
||||
this->item_creator = make_shared<ItemCreator>(
|
||||
common_item_set,
|
||||
rare_item_set,
|
||||
s->common_item_set(version, nullptr),
|
||||
s->rare_item_set(version, nullptr),
|
||||
s->armor_random_set,
|
||||
s->tool_random_set,
|
||||
s->weapon_random_sets.at(this->lobby_difficulty),
|
||||
|
||||
+2
-7
@@ -47,12 +47,7 @@ struct ProxySession {
|
||||
int64_t remote_guild_card_number = -1;
|
||||
parray<uint8_t, 0x28> remote_client_config_data;
|
||||
|
||||
enum class DropMode {
|
||||
DISABLED = 0,
|
||||
PASSTHROUGH,
|
||||
INTERCEPT,
|
||||
};
|
||||
DropMode drop_mode = DropMode::PASSTHROUGH;
|
||||
ProxyDropMode drop_mode = ProxyDropMode::PASSTHROUGH;
|
||||
std::shared_ptr<std::string> quest_dat_data;
|
||||
std::shared_ptr<ItemCreator> item_creator;
|
||||
std::shared_ptr<MapState> map_state;
|
||||
@@ -80,7 +75,7 @@ struct ProxySession {
|
||||
};
|
||||
std::unordered_map<std::string, SavingFile> saving_files;
|
||||
|
||||
void set_drop_mode(std::shared_ptr<ServerState> s, Version version, int64_t override_random_seed, DropMode new_mode);
|
||||
void set_drop_mode(std::shared_ptr<ServerState> s, Version version, int64_t override_random_seed, ProxyDropMode new_mode);
|
||||
|
||||
void clear_lobby_players(size_t num_slots);
|
||||
};
|
||||
|
||||
+70
-7
@@ -221,6 +221,15 @@ void VersionedQuest::assert_valid() const {
|
||||
if (!is_ep3(this->version) && !this->map_file) {
|
||||
throw runtime_error("parsed map file is missing");
|
||||
}
|
||||
if (this->common_item_set_name.empty() != !this->common_item_set) {
|
||||
throw runtime_error("common item set name/pointer mismatch");
|
||||
}
|
||||
if (this->rare_item_set_name.empty() != !this->rare_item_set) {
|
||||
throw runtime_error("rare item set name/pointer mismatch");
|
||||
}
|
||||
if (this->allowed_drop_modes && !(this->allowed_drop_modes & (1 << static_cast<size_t>(this->default_drop_mode)))) {
|
||||
throw runtime_error("default drop mode is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
string VersionedQuest::bin_filename() const {
|
||||
@@ -280,7 +289,13 @@ Quest::Quest(shared_ptr<const VersionedQuest> initial_version)
|
||||
challenge_template_index(initial_version->challenge_template_index),
|
||||
description_flag(initial_version->description_flag),
|
||||
available_expression(initial_version->available_expression),
|
||||
enabled_expression(initial_version->enabled_expression) {
|
||||
enabled_expression(initial_version->enabled_expression),
|
||||
common_item_set_name(initial_version->common_item_set_name),
|
||||
rare_item_set_name(initial_version->rare_item_set_name),
|
||||
common_item_set(initial_version->common_item_set),
|
||||
rare_item_set(initial_version->rare_item_set),
|
||||
allowed_drop_modes(initial_version->allowed_drop_modes),
|
||||
default_drop_mode(initial_version->default_drop_mode) {
|
||||
this->add_version(initial_version);
|
||||
}
|
||||
|
||||
@@ -298,10 +313,6 @@ phosg::JSON Quest::json() const {
|
||||
}));
|
||||
}
|
||||
|
||||
auto battle_rules_json = this->battle_rules ? this->battle_rules->json() : nullptr;
|
||||
auto challenge_template_index_json = (this->challenge_template_index >= 0)
|
||||
? this->challenge_template_index
|
||||
: phosg::JSON(nullptr);
|
||||
return phosg::JSON::dict({
|
||||
{"Number", this->quest_number},
|
||||
{"CategoryID", this->category_id},
|
||||
@@ -311,11 +322,15 @@ phosg::JSON Quest::json() const {
|
||||
{"MaxPlayers", this->max_players},
|
||||
{"LockStatusRegister", (this->lock_status_register >= 0) ? this->lock_status_register : phosg::JSON(nullptr)},
|
||||
{"Name", this->name},
|
||||
{"BattleRules", std::move(battle_rules_json)},
|
||||
{"ChallengeTemplateIndex", std::move(challenge_template_index_json)},
|
||||
{"BattleRules", this->battle_rules ? this->battle_rules->json() : phosg::JSON(nullptr)},
|
||||
{"ChallengeTemplateIndex", (this->challenge_template_index >= 0) ? this->challenge_template_index : phosg::JSON(nullptr)},
|
||||
{"DescriptionFlag", this->description_flag},
|
||||
{"AvailableExpression", this->available_expression ? this->available_expression->str() : phosg::JSON(nullptr)},
|
||||
{"EnabledExpression", this->available_expression ? this->available_expression->str() : phosg::JSON(nullptr)},
|
||||
{"CommonItemSetName", this->common_item_set_name.empty() ? phosg::JSON(nullptr) : this->common_item_set_name},
|
||||
{"RareItemSetName", this->rare_item_set_name.empty() ? phosg::JSON(nullptr) : this->rare_item_set_name},
|
||||
{"AllowedDropModes", this->allowed_drop_modes},
|
||||
{"DefaultDropMode", phosg::name_for_enum(this->default_drop_mode)},
|
||||
{"Versions", std::move(versions_json)},
|
||||
});
|
||||
}
|
||||
@@ -406,6 +421,30 @@ void Quest::add_version(shared_ptr<const VersionedQuest> vq) {
|
||||
"quest version has a different enabled expression (existing: {}, new: {})",
|
||||
existing_str, new_str));
|
||||
}
|
||||
if (this->common_item_set_name != vq->common_item_set_name) {
|
||||
throw runtime_error(std::format(
|
||||
"quest version has different common table name (existing: {}, new: {})",
|
||||
this->common_item_set_name, vq->common_item_set_name));
|
||||
}
|
||||
if (this->common_item_set != vq->common_item_set) {
|
||||
throw runtime_error("quest version has different common table");
|
||||
}
|
||||
if (this->rare_item_set_name != vq->rare_item_set_name) {
|
||||
throw runtime_error(std::format(
|
||||
"quest version has different rare table name (existing: {}, new: {})",
|
||||
this->rare_item_set_name, vq->rare_item_set_name));
|
||||
}
|
||||
if (this->rare_item_set != vq->rare_item_set) {
|
||||
throw runtime_error("quest version has different rare table");
|
||||
}
|
||||
if (this->allowed_drop_modes != vq->allowed_drop_modes) {
|
||||
throw runtime_error(format("quest version has different allowed drop modes (existing: {:02X}, new: {:02X})",
|
||||
this->allowed_drop_modes, vq->allowed_drop_modes));
|
||||
}
|
||||
if (this->default_drop_mode != vq->default_drop_mode) {
|
||||
throw runtime_error(format("quest version has different default drop mode (existing: {}, new: {})",
|
||||
phosg::name_for_enum(this->default_drop_mode), phosg::name_for_enum(vq->default_drop_mode)));
|
||||
}
|
||||
|
||||
this->versions.emplace(this->versions_key(vq->version, vq->language), vq);
|
||||
}
|
||||
@@ -482,6 +521,8 @@ shared_ptr<const VersionedQuest> Quest::version(Version v, uint8_t language) con
|
||||
QuestIndex::QuestIndex(
|
||||
const string& directory,
|
||||
shared_ptr<const QuestCategoryIndex> category_index,
|
||||
const unordered_map<string, shared_ptr<const CommonItemSet>>& common_item_sets,
|
||||
const unordered_map<string, shared_ptr<const RareItemSet>>& rare_item_sets,
|
||||
bool is_ep3)
|
||||
: directory(directory),
|
||||
category_index(category_index) {
|
||||
@@ -914,6 +955,28 @@ QuestIndex::QuestIndex(
|
||||
vq->lock_status_register = metadata_json.get_int("LockStatusRegister");
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
vq->common_item_set_name = metadata_json.at("CommonItemSetName").as_string();
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
if (!vq->common_item_set_name.empty()) {
|
||||
vq->common_item_set = common_item_sets.at(vq->common_item_set_name);
|
||||
}
|
||||
try {
|
||||
vq->rare_item_set_name = metadata_json.at("RareItemSetName").as_string();
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
if (!vq->rare_item_set_name.empty()) {
|
||||
vq->rare_item_set = rare_item_sets.at(vq->rare_item_set_name);
|
||||
}
|
||||
try {
|
||||
vq->allowed_drop_modes = metadata_json.at("AllowedDropModes").as_int();
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
vq->default_drop_mode = phosg::enum_for_name<ServerDropMode>(metadata_json.at("DefaultDropMode").as_string());
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
}
|
||||
|
||||
vq->assert_valid();
|
||||
|
||||
+22
-1
@@ -8,10 +8,13 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "CommonItemSet.hh"
|
||||
#include "IntegralExpression.hh"
|
||||
#include "ItemParameterTable.hh"
|
||||
#include "Map.hh"
|
||||
#include "PlayerSubordinates.hh"
|
||||
#include "QuestScript.hh"
|
||||
#include "RareItemSet.hh"
|
||||
#include "StaticGameData.hh"
|
||||
#include "TeamIndex.hh"
|
||||
|
||||
@@ -87,6 +90,12 @@ struct VersionedQuest {
|
||||
std::shared_ptr<const IntegralExpression> enabled_expression;
|
||||
bool allow_start_from_chat_command = false;
|
||||
int16_t lock_status_register = -1;
|
||||
std::string common_item_set_name;
|
||||
std::string rare_item_set_name;
|
||||
std::shared_ptr<const CommonItemSet> common_item_set;
|
||||
std::shared_ptr<const RareItemSet> rare_item_set;
|
||||
uint8_t allowed_drop_modes = 0x00; // 0 = use server default
|
||||
ServerDropMode default_drop_mode = ServerDropMode::CLIENT; // Ignored if allowed_drop_modes == 0
|
||||
bool is_dlq_encoded = false;
|
||||
|
||||
void assert_valid() const;
|
||||
@@ -115,6 +124,13 @@ struct Quest {
|
||||
uint8_t description_flag;
|
||||
std::shared_ptr<const IntegralExpression> available_expression;
|
||||
std::shared_ptr<const IntegralExpression> enabled_expression;
|
||||
std::string common_item_set_name;
|
||||
std::string rare_item_set_name;
|
||||
std::shared_ptr<const CommonItemSet> common_item_set;
|
||||
std::shared_ptr<const RareItemSet> rare_item_set;
|
||||
uint8_t allowed_drop_modes = 0x00; // 0 = use server default
|
||||
ServerDropMode default_drop_mode = ServerDropMode::CLIENT; // Ignored if allowed_drop_modes == 0
|
||||
|
||||
std::map<uint32_t, std::shared_ptr<const VersionedQuest>> versions;
|
||||
|
||||
Quest() = delete;
|
||||
@@ -151,7 +167,12 @@ struct QuestIndex {
|
||||
std::map<std::string, std::shared_ptr<Quest>> quests_by_name;
|
||||
std::map<uint32_t, std::map<uint32_t, std::shared_ptr<Quest>>> quests_by_category_id_and_number;
|
||||
|
||||
QuestIndex(const std::string& directory, std::shared_ptr<const QuestCategoryIndex> category_index, bool is_ep3);
|
||||
QuestIndex(
|
||||
const std::string& directory,
|
||||
std::shared_ptr<const QuestCategoryIndex> category_index,
|
||||
const std::unordered_map<std::string, std::shared_ptr<const CommonItemSet>>& common_item_sets,
|
||||
const std::unordered_map<std::string, std::shared_ptr<const RareItemSet>>& rare_item_sets,
|
||||
bool is_ep3);
|
||||
phosg::JSON json() const;
|
||||
|
||||
std::shared_ptr<const Quest> get(uint32_t quest_number) const;
|
||||
|
||||
+12
-8
@@ -2252,19 +2252,19 @@ static asio::awaitable<void> on_09(shared_ptr<Client> c, Channel::Message& msg)
|
||||
}
|
||||
|
||||
switch (game->drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
info += "$C6Drops disabled$C7\n";
|
||||
break;
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::CLIENT:
|
||||
info += "$C6Client drops$C7\n";
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
info += "$C6Server drops$C7\n";
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
info += "$C6Private drops$C7\n";
|
||||
break;
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
info += "$C6Duplicate drops$C7\n";
|
||||
break;
|
||||
}
|
||||
@@ -2433,6 +2433,10 @@ void set_lobby_quest(shared_ptr<Lobby> l, shared_ptr<const Quest> q, bool substi
|
||||
if (l->episode != Episode::EP3) {
|
||||
l->episode = q->episode;
|
||||
}
|
||||
if (l->quest->allowed_drop_modes) {
|
||||
l->allowed_drop_modes = l->quest->allowed_drop_modes;
|
||||
l->drop_mode = l->quest->default_drop_mode;
|
||||
}
|
||||
l->create_item_creator();
|
||||
|
||||
size_t num_clients_with_loading_flag = 0;
|
||||
@@ -4585,7 +4589,7 @@ shared_ptr<Lobby> create_game_generic(
|
||||
case Version::GC_EP3_NTE:
|
||||
case Version::GC_EP3:
|
||||
quest_flag_rewrites = nullptr;
|
||||
game->drop_mode = Lobby::DropMode::DISABLED;
|
||||
game->drop_mode = ServerDropMode::DISABLED;
|
||||
game->allowed_drop_modes = (1 << static_cast<size_t>(game->drop_mode));
|
||||
break;
|
||||
case Version::BB_V4:
|
||||
@@ -4601,10 +4605,10 @@ shared_ptr<Lobby> create_game_generic(
|
||||
game->allowed_drop_modes = s->allowed_drop_modes_v4_normal;
|
||||
}
|
||||
// Disallow CLIENT mode on BB
|
||||
if (game->drop_mode == Lobby::DropMode::CLIENT) {
|
||||
if (game->drop_mode == ServerDropMode::CLIENT) {
|
||||
throw logic_error("CLIENT mode not allowed on BB");
|
||||
}
|
||||
if (game->allowed_drop_modes & (1 << static_cast<size_t>(Lobby::DropMode::CLIENT))) {
|
||||
if (game->allowed_drop_modes & (1 << static_cast<size_t>(ServerDropMode::CLIENT))) {
|
||||
throw logic_error("CLIENT mode not allowed on BB");
|
||||
}
|
||||
break;
|
||||
|
||||
+16
-16
@@ -2186,7 +2186,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, SubcommandMessage&
|
||||
throw runtime_error("BB client sent 6x5F command");
|
||||
}
|
||||
|
||||
bool should_notify = s->rare_notifs_enabled_for_client_drops && (l->drop_mode == Lobby::DropMode::CLIENT);
|
||||
bool should_notify = s->rare_notifs_enabled_for_client_drops && (l->drop_mode == ServerDropMode::CLIENT);
|
||||
|
||||
shared_ptr<const MapState::EnemyState> ene_st;
|
||||
shared_ptr<const MapState::ObjectState> obj_st;
|
||||
@@ -2956,27 +2956,27 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
|
||||
G_SpecializableItemDropRequest_6xA2 cmd = normalize_drop_request(msg.data, msg.size);
|
||||
auto rec = reconcile_drop_request_with_map(c, cmd, l->episode, l->event, l->map_state, true);
|
||||
|
||||
Lobby::DropMode drop_mode = l->drop_mode;
|
||||
ServerDropMode drop_mode = l->drop_mode;
|
||||
switch (drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case ServerDropMode::DISABLED:
|
||||
co_return;
|
||||
case Lobby::DropMode::CLIENT: {
|
||||
case ServerDropMode::CLIENT: {
|
||||
// If the leader is BB, use SERVER_SHARED instead
|
||||
// TODO: We should also use server drops if any clients have incompatible
|
||||
// object lists, since they might generate incorrect IDs for items and we
|
||||
// can't override them
|
||||
auto leader = l->clients[l->leader_id];
|
||||
if (leader && leader->version() == Version::BB_V4) {
|
||||
drop_mode = Lobby::DropMode::SERVER_SHARED;
|
||||
drop_mode = ServerDropMode::SERVER_SHARED;
|
||||
break;
|
||||
} else {
|
||||
forward_subcommand(c, msg);
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case Lobby::DropMode::SERVER_DUPLICATE:
|
||||
case Lobby::DropMode::SERVER_PRIVATE:
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_DUPLICATE:
|
||||
case ServerDropMode::SERVER_PRIVATE:
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid drop mode");
|
||||
@@ -3016,11 +3016,11 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
|
||||
};
|
||||
|
||||
switch (drop_mode) {
|
||||
case Lobby::DropMode::DISABLED:
|
||||
case Lobby::DropMode::CLIENT:
|
||||
case ServerDropMode::DISABLED:
|
||||
case ServerDropMode::CLIENT:
|
||||
throw logic_error("unhandled simple drop mode");
|
||||
case Lobby::DropMode::SERVER_SHARED:
|
||||
case Lobby::DropMode::SERVER_DUPLICATE: {
|
||||
case ServerDropMode::SERVER_SHARED:
|
||||
case ServerDropMode::SERVER_DUPLICATE: {
|
||||
// TODO: In SERVER_DUPLICATE mode, should we reduce the rates for rare
|
||||
// items? Maybe by a factor of l->count_clients()?
|
||||
auto res = generate_item();
|
||||
@@ -3029,7 +3029,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
|
||||
} else {
|
||||
string name = s->describe_item(c->version(), res.item);
|
||||
l->log.info_f("Entity {:04X} (area {:02X}) created item {}", cmd.entity_index, cmd.effective_area, name);
|
||||
if (drop_mode == Lobby::DropMode::SERVER_DUPLICATE) {
|
||||
if (drop_mode == ServerDropMode::SERVER_DUPLICATE) {
|
||||
for (const auto& lc : l->clients) {
|
||||
if (lc && (rec.obj_st || (lc->floor == cmd.floor))) {
|
||||
res.item.id = l->generate_item_id(0xFF);
|
||||
@@ -3058,7 +3058,7 @@ static asio::awaitable<void> on_entity_drop_item_request(shared_ptr<Client> c, S
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lobby::DropMode::SERVER_PRIVATE: {
|
||||
case ServerDropMode::SERVER_PRIVATE: {
|
||||
for (const auto& lc : l->clients) {
|
||||
if (lc && (rec.obj_st || (lc->floor == cmd.floor))) {
|
||||
auto res = generate_item();
|
||||
@@ -3135,7 +3135,7 @@ static asio::awaitable<void> on_set_quest_flag(shared_ptr<Client> c, SubcommandM
|
||||
|
||||
forward_subcommand(c, msg);
|
||||
|
||||
if (l->drop_mode != Lobby::DropMode::DISABLED) {
|
||||
if (l->drop_mode != ServerDropMode::DISABLED) {
|
||||
EnemyType boss_enemy_type = EnemyType::NONE;
|
||||
bool is_ep2 = (l->episode == Episode::EP2);
|
||||
if ((l->episode == Episode::EP1) && (c->floor == 0x0E)) {
|
||||
@@ -4916,7 +4916,7 @@ static asio::awaitable<void> on_photon_crystal_exchange_bb(shared_ptr<Client> c,
|
||||
size_t index = p->inventory.find_item_by_primary_identifier(0x03100200);
|
||||
auto item = p->remove_item(p->inventory.items[index].data.id, 1, *s->item_stack_limits(c->version()));
|
||||
send_destroy_item_to_lobby(c, item.id, 1);
|
||||
l->drop_mode = Lobby::DropMode::DISABLED;
|
||||
l->drop_mode = ServerDropMode::DISABLED;
|
||||
l->allowed_drop_modes = (1 << static_cast<uint8_t>(l->drop_mode)); // DISABLED only
|
||||
co_return;
|
||||
}
|
||||
|
||||
+137
-72
@@ -512,6 +512,35 @@ ItemData ServerState::parse_item_description(Version version, const string& desc
|
||||
return this->item_name_index(version)->parse_item_description(description);
|
||||
}
|
||||
|
||||
shared_ptr<const CommonItemSet> ServerState::common_item_set(Version logic_version, shared_ptr<const Quest> q) const {
|
||||
if (q && q->common_item_set) {
|
||||
return q->common_item_set;
|
||||
} else if (is_v1_or_v2(logic_version)) {
|
||||
// TODO: We should probably have a v1 common item set at some point too
|
||||
return this->common_item_sets.at("common-table-v1-v2");
|
||||
} else if (is_v3(logic_version) || is_v4(logic_version)) {
|
||||
return this->common_item_sets.at("common-table-v3-v4");
|
||||
} else {
|
||||
throw runtime_error(std::format("no default common item set is available for {}", phosg::name_for_enum(logic_version)));
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<const RareItemSet> ServerState::rare_item_set(Version logic_version, shared_ptr<const Quest> q) const {
|
||||
if (q && q->rare_item_set) {
|
||||
return q->rare_item_set;
|
||||
} else if (is_v1(logic_version)) {
|
||||
return this->rare_item_sets.at("rare-table-v1");
|
||||
} else if (is_v2(logic_version)) {
|
||||
return this->rare_item_sets.at("rare-table-v2");
|
||||
} else if (is_v3(logic_version)) {
|
||||
return this->rare_item_sets.at("rare-table-v3");
|
||||
} else if (is_v4(logic_version)) {
|
||||
return this->rare_item_sets.at("rare-table-v4");
|
||||
} else {
|
||||
throw runtime_error(std::format("no default rare item set is available for {}", phosg::name_for_enum(logic_version)));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerState::set_port_configuration(const vector<PortConfiguration>& port_configs) {
|
||||
this->name_to_port_config.clear();
|
||||
this->number_to_port_config.clear();
|
||||
@@ -835,22 +864,22 @@ void ServerState::load_config_early() {
|
||||
this->allowed_drop_modes_v4_normal = this->config_json->get_int("AllowedDropModesV4Normal", 0x1D);
|
||||
this->allowed_drop_modes_v4_battle = this->config_json->get_int("AllowedDropModesV4Battle", 0x05);
|
||||
this->allowed_drop_modes_v4_challenge = this->config_json->get_int("AllowedDropModesV4Challenge", 0x05);
|
||||
this->default_drop_mode_v1_v2_normal = this->config_json->get_enum("DefaultDropModeV1V2Normal", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v1_v2_battle = this->config_json->get_enum("DefaultDropModeV1V2Battle", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v1_v2_challenge = this->config_json->get_enum("DefaultDropModeV1V2Challenge", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v3_normal = this->config_json->get_enum("DefaultDropModeV3Normal", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v3_battle = this->config_json->get_enum("DefaultDropModeV3Battle", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v3_challenge = this->config_json->get_enum("DefaultDropModeV3Challenge", Lobby::DropMode::CLIENT);
|
||||
this->default_drop_mode_v4_normal = this->config_json->get_enum("DefaultDropModeV4Normal", Lobby::DropMode::SERVER_SHARED);
|
||||
this->default_drop_mode_v4_battle = this->config_json->get_enum("DefaultDropModeV4Battle", Lobby::DropMode::SERVER_SHARED);
|
||||
this->default_drop_mode_v4_challenge = this->config_json->get_enum("DefaultDropModeV4Challenge", Lobby::DropMode::SERVER_SHARED);
|
||||
if ((this->default_drop_mode_v4_normal == Lobby::DropMode::CLIENT) ||
|
||||
(this->default_drop_mode_v4_battle == Lobby::DropMode::CLIENT) ||
|
||||
(this->default_drop_mode_v4_challenge == Lobby::DropMode::CLIENT)) {
|
||||
this->default_drop_mode_v1_v2_normal = this->config_json->get_enum("DefaultDropModeV1V2Normal", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v1_v2_battle = this->config_json->get_enum("DefaultDropModeV1V2Battle", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v1_v2_challenge = this->config_json->get_enum("DefaultDropModeV1V2Challenge", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v3_normal = this->config_json->get_enum("DefaultDropModeV3Normal", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v3_battle = this->config_json->get_enum("DefaultDropModeV3Battle", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v3_challenge = this->config_json->get_enum("DefaultDropModeV3Challenge", ServerDropMode::CLIENT);
|
||||
this->default_drop_mode_v4_normal = this->config_json->get_enum("DefaultDropModeV4Normal", ServerDropMode::SERVER_SHARED);
|
||||
this->default_drop_mode_v4_battle = this->config_json->get_enum("DefaultDropModeV4Battle", ServerDropMode::SERVER_SHARED);
|
||||
this->default_drop_mode_v4_challenge = this->config_json->get_enum("DefaultDropModeV4Challenge", ServerDropMode::SERVER_SHARED);
|
||||
if ((this->default_drop_mode_v4_normal == ServerDropMode::CLIENT) ||
|
||||
(this->default_drop_mode_v4_battle == ServerDropMode::CLIENT) ||
|
||||
(this->default_drop_mode_v4_challenge == ServerDropMode::CLIENT)) {
|
||||
throw runtime_error("default V4 drop mode cannot be CLIENT");
|
||||
}
|
||||
if ((this->allowed_drop_modes_v4_normal & (1 << static_cast<size_t>(Lobby::DropMode::CLIENT))) ||
|
||||
(this->allowed_drop_modes_v4_battle & (1 << static_cast<size_t>(Lobby::DropMode::CLIENT))) || (this->allowed_drop_modes_v4_challenge & (1 << static_cast<size_t>(Lobby::DropMode::CLIENT)))) {
|
||||
if ((this->allowed_drop_modes_v4_normal & (1 << static_cast<size_t>(ServerDropMode::CLIENT))) ||
|
||||
(this->allowed_drop_modes_v4_battle & (1 << static_cast<size_t>(ServerDropMode::CLIENT))) || (this->allowed_drop_modes_v4_challenge & (1 << static_cast<size_t>(ServerDropMode::CLIENT)))) {
|
||||
throw runtime_error("CLIENT drop mode cannot be allowed in V4");
|
||||
}
|
||||
|
||||
@@ -1940,61 +1969,103 @@ void ServerState::load_item_name_indexes() {
|
||||
}
|
||||
|
||||
void ServerState::load_drop_tables() {
|
||||
config_log.info_f("Loading rare item sets");
|
||||
config_log.info_f("Loading item sets");
|
||||
|
||||
unordered_map<string, shared_ptr<RareItemSet>> new_rare_item_sets;
|
||||
unordered_map<string, shared_ptr<const RareItemSet>> new_rare_item_sets;
|
||||
unordered_map<string, shared_ptr<const CommonItemSet>> new_common_item_sets;
|
||||
for (const auto& item : std::filesystem::directory_iterator("system/item-tables")) {
|
||||
string filename = item.path().filename().string();
|
||||
if (!filename.starts_with("rare-table-")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string path = "system/item-tables/" + filename;
|
||||
size_t ext_offset = filename.rfind('.');
|
||||
string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset);
|
||||
if (filename.starts_with("common-table-") || filename.starts_with("ItemPT-")) {
|
||||
string path = "system/item-tables/" + filename;
|
||||
size_t ext_offset = filename.rfind('.');
|
||||
string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset);
|
||||
|
||||
if (filename.ends_with("-v1.json")) {
|
||||
config_log.info_f("Loading v1 JSON rare item table {}", filename);
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::DC_V1)));
|
||||
} else if (filename.ends_with("-v2.json")) {
|
||||
config_log.info_f("Loading v2 JSON rare item table {}", filename);
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::PC_V2)));
|
||||
} else if (filename.ends_with("-v3.json")) {
|
||||
config_log.info_f("Loading v3 JSON rare item table {}", filename);
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::GC_V3)));
|
||||
} else if (filename.ends_with("-v4.json")) {
|
||||
config_log.info_f("Loading v4 JSON rare item table {}", filename);
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::BB_V4)));
|
||||
// AFSV2CommonItemSet(std::shared_ptr<const std::string> pt_afs_data, std::shared_ptr<const std::string> ct_afs_data);
|
||||
|
||||
} else if (filename.ends_with(".afs")) {
|
||||
config_log.info_f("Loading AFS rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(AFSArchive(data), false));
|
||||
if (filename.ends_with(".json")) {
|
||||
config_log.info_f("Loading JSON common item table {}", filename);
|
||||
new_common_item_sets.emplace(basename, make_shared<JSONCommonItemSet>(phosg::JSON::parse(phosg::load_file(path))));
|
||||
} else if (filename.ends_with(".afs")) {
|
||||
string ct_filename;
|
||||
if (filename.starts_with("ItemPT-")) {
|
||||
ct_filename = "ItemCT-" + filename.substr(7);
|
||||
} else if (filename.starts_with("common-table-")) {
|
||||
ct_filename = "challenge-common-table-" + filename.substr(13);
|
||||
} else {
|
||||
throw std::runtime_error(std::format("cannot determine challenge table filename for common table file: {}", filename));
|
||||
}
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
shared_ptr<string> ct_data;
|
||||
try {
|
||||
string ct_path = "system/item-tables/" + ct_filename;
|
||||
ct_data = make_shared<string>(phosg::load_file(ct_path));
|
||||
config_log.info_f("Loading AFS common item table {} with challenge table {}", filename, ct_filename);
|
||||
} catch (const phosg::cannot_open_file&) {
|
||||
config_log.info_f("Loading AFS common item table {} without challenge table", filename);
|
||||
}
|
||||
new_common_item_sets.emplace(basename, make_shared<AFSV2CommonItemSet>(data, ct_data));
|
||||
} else if (filename.ends_with(".gsl")) {
|
||||
config_log.info_f("Loading little-endian GSL common item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
new_common_item_sets.emplace(basename, make_shared<GSLV3V4CommonItemSet>(data, false));
|
||||
} else if (filename.ends_with(".gslb")) {
|
||||
config_log.info_f("Loading big-endian GSL common item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
new_common_item_sets.emplace(basename, make_shared<GSLV3V4CommonItemSet>(data, true));
|
||||
} else {
|
||||
throw std::runtime_error(std::format("unknown format for common table file: {}", filename));
|
||||
}
|
||||
|
||||
} else if (filename.ends_with(".gsl")) {
|
||||
config_log.info_f("Loading GSL rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(GSLArchive(data, false), false));
|
||||
} else if (filename.starts_with("rare-table-") || filename.starts_with("ItemRT-")) {
|
||||
string path = "system/item-tables/" + filename;
|
||||
size_t ext_offset = filename.rfind('.');
|
||||
string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset);
|
||||
|
||||
} else if (filename.ends_with(".gslb")) {
|
||||
config_log.info_f("Loading GSL rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(GSLArchive(data, true), true));
|
||||
shared_ptr<RareItemSet> rare_set;
|
||||
if (filename.ends_with("-v1.json")) {
|
||||
config_log.info_f("Loading v1 JSON rare item table {}", filename);
|
||||
rare_set = make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::DC_V1));
|
||||
} else if (filename.ends_with("-v2.json")) {
|
||||
config_log.info_f("Loading v2 JSON rare item table {}", filename);
|
||||
rare_set = make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::PC_V2));
|
||||
} else if (filename.ends_with("-v3.json")) {
|
||||
config_log.info_f("Loading v3 JSON rare item table {}", filename);
|
||||
rare_set = make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::GC_V3));
|
||||
} else if (filename.ends_with("-v4.json")) {
|
||||
config_log.info_f("Loading v4 JSON rare item table {}", filename);
|
||||
rare_set = make_shared<RareItemSet>(phosg::JSON::parse(phosg::load_file(path)), this->item_name_index(Version::BB_V4));
|
||||
|
||||
} else if (filename.ends_with(".rel")) {
|
||||
config_log.info_f("Loading REL rare item table {}", filename);
|
||||
new_rare_item_sets.emplace(basename, make_shared<RareItemSet>(phosg::load_file(path), true));
|
||||
} else if (filename.ends_with(".afs")) {
|
||||
config_log.info_f("Loading AFS rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
rare_set = make_shared<RareItemSet>(AFSArchive(data), false);
|
||||
|
||||
} else if (filename.ends_with(".gsl")) {
|
||||
config_log.info_f("Loading GSL rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
rare_set = make_shared<RareItemSet>(GSLArchive(data, false), false);
|
||||
|
||||
} else if (filename.ends_with(".gslb")) {
|
||||
config_log.info_f("Loading GSL rare item table {}", filename);
|
||||
auto data = make_shared<string>(phosg::load_file(path));
|
||||
rare_set = make_shared<RareItemSet>(GSLArchive(data, true), true);
|
||||
|
||||
} else if (filename.ends_with(".rel")) {
|
||||
config_log.info_f("Loading REL rare item table {}", filename);
|
||||
rare_set = make_shared<RareItemSet>(phosg::load_file(path), true);
|
||||
|
||||
} else {
|
||||
throw std::runtime_error(std::format("unknown format for rare table file: {}", filename));
|
||||
}
|
||||
|
||||
if (this->server_global_drop_rate_multiplier != 1.0) {
|
||||
rare_set->multiply_all_rates(this->server_global_drop_rate_multiplier);
|
||||
}
|
||||
new_rare_item_sets.emplace(basename, std::move(rare_set));
|
||||
}
|
||||
}
|
||||
|
||||
config_log.info_f("Loading v2 common item table");
|
||||
auto ct_data_v2 = make_shared<string>(phosg::load_file("system/item-tables/ItemCT-pc-v2.afs"));
|
||||
auto pt_data_v2 = make_shared<string>(phosg::load_file("system/item-tables/ItemPT-pc-v2.afs"));
|
||||
auto new_common_item_set_v2 = make_shared<AFSV2CommonItemSet>(pt_data_v2, ct_data_v2);
|
||||
config_log.info_f("Loading v3+v4 common item table");
|
||||
auto pt_data_v3_v4 = make_shared<string>(phosg::load_file("system/item-tables/ItemPT-gc-v3.gsl"));
|
||||
auto new_common_item_set_v3_v4 = make_shared<GSLV3V4CommonItemSet>(pt_data_v3_v4, true);
|
||||
|
||||
config_log.info_f("Loading armor table");
|
||||
auto armor_data = make_shared<string>(phosg::load_file("system/item-tables/ArmorRandom-gc-v3.rel"));
|
||||
auto new_armor_random_set = make_shared<ArmorRandomSet>(armor_data);
|
||||
@@ -2020,19 +2091,8 @@ void ServerState::load_drop_tables() {
|
||||
auto tekker_data = make_shared<string>(phosg::load_file("system/item-tables/JudgeItem-gc-v3.rel"));
|
||||
auto new_tekker_adjustment_set = make_shared<TekkerAdjustmentSet>(tekker_data);
|
||||
|
||||
if (this->server_global_drop_rate_multiplier != 1.0) {
|
||||
for (auto& it : new_rare_item_sets) {
|
||||
it.second->multiply_all_rates(this->server_global_drop_rate_multiplier);
|
||||
}
|
||||
}
|
||||
// We can't just std::move() new_rare_item_sets into place because its values are
|
||||
// not const :(
|
||||
this->rare_item_sets.clear();
|
||||
for (auto& it : new_rare_item_sets) {
|
||||
this->rare_item_sets.emplace(it.first, std::move(it.second));
|
||||
}
|
||||
this->common_item_set_v2 = std::move(new_common_item_set_v2);
|
||||
this->common_item_set_v3_v4 = std::move(new_common_item_set_v3_v4);
|
||||
this->rare_item_sets = std::move(new_rare_item_sets);
|
||||
this->common_item_sets = std::move(new_common_item_sets);
|
||||
this->armor_random_set = std::move(new_armor_random_set);
|
||||
this->tool_random_set = std::move(new_tool_random_set);
|
||||
this->weapon_random_sets = std::move(new_weapon_random_sets);
|
||||
@@ -2107,9 +2167,14 @@ void ServerState::load_ep3_tournament_state() {
|
||||
|
||||
void ServerState::load_quest_index() {
|
||||
config_log.info_f("Collecting quests");
|
||||
this->default_quest_index = make_shared<QuestIndex>("system/quests", this->quest_category_index, false);
|
||||
this->default_quest_index = make_shared<QuestIndex>("system/quests", this->quest_category_index, this->common_item_sets, this->rare_item_sets, false);
|
||||
config_log.info_f("Collecting Episode 3 download quests");
|
||||
this->ep3_download_quest_index = make_shared<QuestIndex>("system/ep3/maps-download", this->quest_category_index, true);
|
||||
this->ep3_download_quest_index = make_shared<QuestIndex>(
|
||||
"system/ep3/maps-download",
|
||||
this->quest_category_index,
|
||||
unordered_map<string, shared_ptr<const CommonItemSet>>{},
|
||||
unordered_map<string, shared_ptr<const RareItemSet>>{},
|
||||
true);
|
||||
}
|
||||
|
||||
void ServerState::compile_functions() {
|
||||
|
||||
+13
-11
@@ -128,15 +128,15 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
uint8_t allowed_drop_modes_v4_normal = 0x1D; // CLIENT not allowed
|
||||
uint8_t allowed_drop_modes_v4_battle = 0x05;
|
||||
uint8_t allowed_drop_modes_v4_challenge = 0x05;
|
||||
Lobby::DropMode default_drop_mode_v1_v2_normal = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v1_v2_battle = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v1_v2_challenge = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v3_normal = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v3_battle = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v3_challenge = Lobby::DropMode::CLIENT;
|
||||
Lobby::DropMode default_drop_mode_v4_normal = Lobby::DropMode::SERVER_SHARED;
|
||||
Lobby::DropMode default_drop_mode_v4_battle = Lobby::DropMode::SERVER_SHARED;
|
||||
Lobby::DropMode default_drop_mode_v4_challenge = Lobby::DropMode::SERVER_SHARED;
|
||||
ServerDropMode default_drop_mode_v1_v2_normal = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v1_v2_battle = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v1_v2_challenge = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v3_normal = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v3_battle = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v3_challenge = ServerDropMode::CLIENT;
|
||||
ServerDropMode default_drop_mode_v4_normal = ServerDropMode::SERVER_SHARED;
|
||||
ServerDropMode default_drop_mode_v4_battle = ServerDropMode::SERVER_SHARED;
|
||||
ServerDropMode default_drop_mode_v4_challenge = ServerDropMode::SERVER_SHARED;
|
||||
std::unordered_map<uint16_t, IntegralExpression> quest_flag_rewrites_v1_v2;
|
||||
std::unordered_map<uint16_t, IntegralExpression> quest_flag_rewrites_v3;
|
||||
std::unordered_map<uint16_t, IntegralExpression> quest_flag_rewrites_v4;
|
||||
@@ -196,9 +196,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::shared_ptr<const LevelTable> level_table_v4;
|
||||
std::shared_ptr<const BattleParamsIndex> battle_params;
|
||||
std::shared_ptr<const GSLArchive> bb_data_gsl;
|
||||
std::unordered_map<std::string, std::shared_ptr<const CommonItemSet>> common_item_sets;
|
||||
std::unordered_map<std::string, std::shared_ptr<const RareItemSet>> rare_item_sets;
|
||||
std::shared_ptr<const CommonItemSet> common_item_set_v2;
|
||||
std::shared_ptr<const CommonItemSet> common_item_set_v3_v4;
|
||||
std::shared_ptr<const ArmorRandomSet> armor_random_set;
|
||||
std::shared_ptr<const ToolRandomSet> tool_random_set;
|
||||
std::array<std::shared_ptr<const WeaponRandomSet>, 4> weapon_random_sets;
|
||||
@@ -357,6 +356,9 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::string describe_item(Version version, const ItemData& item, uint8_t flags = 0) const;
|
||||
ItemData parse_item_description(Version version, const std::string& description) const;
|
||||
|
||||
std::shared_ptr<const CommonItemSet> common_item_set(Version logic_version, std::shared_ptr<const Quest> q) const;
|
||||
std::shared_ptr<const RareItemSet> rare_item_set(Version logic_version, std::shared_ptr<const Quest> q) const;
|
||||
|
||||
const std::vector<uint32_t>& public_lobby_search_order(Version version, bool is_client_customization) const;
|
||||
inline const std::vector<uint32_t>& public_lobby_search_order(std::shared_ptr<const Client> c) const {
|
||||
return this->public_lobby_search_order(c->version(), c->check_flag(Client::Flag::IS_CLIENT_CUSTOMIZATION));
|
||||
|
||||
Reference in New Issue
Block a user