From b82be91edd5aeea69bf02330d486e10b39156533 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Tue, 29 Nov 2022 21:26:11 -0800 Subject: [PATCH] move ep3 behavior flags into DataIndex --- src/Episode3/DataIndex.cc | 37 ++++++++++++++++++++++++------------- src/Episode3/DataIndex.hh | 19 +++++++++++++++---- src/Episode3/Server.cc | 12 +++++------- src/Episode3/Server.hh | 10 ---------- src/Main.cc | 5 +++-- src/ReceiveCommands.cc | 2 +- system/config.example.json | 3 +++ 7 files changed, 51 insertions(+), 37 deletions(-) diff --git a/src/Episode3/DataIndex.cc b/src/Episode3/DataIndex.cc index 35cc9032..bf2f82ce 100644 --- a/src/Episode3/DataIndex.cc +++ b/src/Episode3/DataIndex.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include "../Loggers.hh" #include "../Compression.hh" @@ -1154,12 +1155,12 @@ bool Rules::check_and_reset_invalid_fields() { -DataIndex::DataIndex(const string& directory, bool debug) - : debug(debug) { +DataIndex::DataIndex(const string& directory, uint32_t behavior_flags) + : behavior_flags(behavior_flags) { unordered_map> card_tags; unordered_map card_text; - if (this->debug) { + if (this->behavior_flags & BehaviorFlag::LOAD_CARD_TEXT) { try { string data = prs_decompress(load_file(directory + "/card-text.mnr")); StringReader r(data); @@ -1248,14 +1249,11 @@ DataIndex::DataIndex(const string& directory, bool debug) string decompressed_data; if (isfile(directory + "/card-definitions.mnrd")) { decompressed_data = load_file(directory + "/card-definitions.mnrd"); - this->compressed_card_definitions = prs_compress(decompressed_data); + this->compressed_card_definitions.clear(); } else { this->compressed_card_definitions = load_file(directory + "/card-definitions.mnr"); decompressed_data = prs_decompress(this->compressed_card_definitions); } - if (this->compressed_card_definitions.size() > 0x7BF8) { - throw runtime_error("compressed card list data is too long"); - } if (decompressed_data.size() > 0x36EC0) { throw runtime_error("decompressed card list data is too long"); } @@ -1266,17 +1264,18 @@ DataIndex::DataIndex(const string& directory, bool debug) "decompressed card update file size %zX is not aligned with card definition size %zX (%zX extra bytes)", decompressed_data.size(), sizeof(CardDefinition), decompressed_data.size() % sizeof(CardDefinition))); } - const auto* def = reinterpret_cast(decompressed_data.data()); + auto* defs = reinterpret_cast(decompressed_data.data()); size_t max_cards = decompressed_data.size() / sizeof(CardDefinition); for (size_t x = 0; x < max_cards; x++) { // The last card entry has the build date and some other metadata (and // isn't a real card, obviously), so skip it. Seems like the card ID is // always a large number that won't fit in a uint16_t, so we use that to // determine if the entry is a real card or not. - if (def[x].card_id & 0xFFFF0000) { + if (defs[x].card_id & 0xFFFF0000) { continue; } - shared_ptr entry(new CardEntry({def[x], {}, {}})); + + shared_ptr entry(new CardEntry({defs[x], {}, {}})); if (!this->card_definitions.emplace(entry->def.card_id, entry).second) { throw runtime_error(string_printf( "duplicate card id: %08" PRIX32, entry->def.card_id.load())); @@ -1293,16 +1292,28 @@ DataIndex::DataIndex(const string& directory, bool debug) entry->def.mv.decode_code(); entry->def.decode_range(); - if (this->debug) { + if (this->behavior_flags & BehaviorFlag::LOAD_CARD_TEXT) { try { - entry->text = move(card_text.at(def[x].card_id)); + entry->text = move(card_text.at(defs[x].card_id)); } catch (const out_of_range&) { } try { - entry->debug_tags = move(card_tags.at(def[x].card_id)); + entry->debug_tags = move(card_tags.at(defs[x].card_id)); } catch (const out_of_range&) { } } } + if (this->compressed_card_definitions.empty()) { + uint64_t start = now(); + this->compressed_card_definitions = prs_compress(decompressed_data); + uint64_t diff = now() - start; + static_game_data_log.info( + "Compressed card definitions (%zu bytes -> %zu bytes) in %" PRIu64 "ms", + decompressed_data.size(), this->compressed_card_definitions.size(), diff); + } + if (this->compressed_card_definitions.size() > 0x7BF8) { + throw runtime_error("compressed card list data is too long"); + } + static_game_data_log.info("Indexed %zu Episode 3 card definitions", this->card_definitions.size()); } catch (const exception& e) { static_game_data_log.warning("Failed to load Episode 3 card update: %s", e.what()); diff --git a/src/Episode3/DataIndex.hh b/src/Episode3/DataIndex.hh index da2134da..5c33d42d 100644 --- a/src/Episode3/DataIndex.hh +++ b/src/Episode3/DataIndex.hh @@ -23,6 +23,17 @@ class DataIndex; +enum BehaviorFlag { + SKIP_DECK_VERIFY = 0x00000001, + IGNORE_CARD_COUNTS = 0x00000002, + SKIP_D1_D2_REPLACE = 0x00000004, + DISABLE_TIME_LIMITS = 0x00000008, + ENABLE_STATUS_MESSAGES = 0x00000010, + LOAD_CARD_TEXT = 0x00000020, +}; + + + enum class StatSwapType : uint8_t { NONE = 0, A_T_SWAP = 1, @@ -462,7 +473,7 @@ struct CardDefinition { be_uint32_t card_id; parray jp_name; - CardType type; // Type enum. If <0, then this is the end of the card list + CardType type; // If <0 (signed), then this is the end of the card list uint8_t self_cost; // ATK dice points required uint8_t ally_cost; // ATK points from allies required; PBs use this uint8_t unused1; @@ -767,7 +778,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests class DataIndex { public: - explicit DataIndex(const std::string& directory, bool debug = false); + DataIndex(const std::string& directory, uint32_t behavior_flags); struct CardEntry { CardDefinition def; @@ -798,9 +809,9 @@ public: std::shared_ptr definition_for_map_number(uint32_t id) const; std::set all_map_ids() const; -private: - bool debug; + const uint32_t behavior_flags; +private: std::string compressed_card_definitions; std::unordered_map> card_definitions; std::unordered_map> card_definitions_by_name; diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index fbcb9c38..57d0ecc5 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -33,11 +33,9 @@ void ServerBase::PresenceEntry::clear() { ServerBase::ServerBase( shared_ptr lobby, shared_ptr data_index, - uint32_t behavior_flags, uint32_t random_seed) : lobby(lobby), data_index(data_index), - behavior_flags(behavior_flags), random_seed(random_seed) { } void ServerBase::init() { @@ -154,7 +152,7 @@ void Server::send(const void* data, size_t size) const { __attribute__((format(printf, 2, 3))) void Server::send_debug_message_printf(const char* fmt, ...) const { auto l = this->base()->lobby.lock(); - if (l && (this->base()->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) { + if (l && (this->base()->data_index->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) { va_list va; va_start(va, fmt); std::string buf = string_vprintf(fmt, va); @@ -1714,7 +1712,7 @@ void Server::handle_6xB3x13_update_map_during_setup(const string& data) { *b->map_and_rules1 = in_cmd.map_and_rules_state; *b->map_and_rules2 = in_cmd.map_and_rules_state; b->overlay_state = in_cmd.overlay_state; - if (b->behavior_flags & BehaviorFlag::DISABLE_TIME_LIMITS) { + if (b->data_index->behavior_flags & BehaviorFlag::DISABLE_TIME_LIMITS) { b->map_and_rules1->rules.overall_time_limit = 0; b->map_and_rules1->rules.phase_time_limit = 0; b->map_and_rules2->rules.overall_time_limit = 0; @@ -1744,9 +1742,9 @@ void Server::handle_6xB3x14_update_deck_during_setup(const string& data) { } DeckEntry entry = in_cmd.entry; int32_t verify_error = 0; - if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) { + if (!(this->base()->data_index->behavior_flags & BehaviorFlag::SKIP_DECK_VERIFY)) { // Note: Sega's original implementation doesn't use the card counts here - if (this->base()->behavior_flags & BehaviorFlag::IGNORE_CARD_COUNTS) { + if (this->base()->data_index->behavior_flags & BehaviorFlag::IGNORE_CARD_COUNTS) { verify_error = this->ruler_server->verify_deck(entry.card_ids); } else { verify_error = this->ruler_server->verify_deck(entry.card_ids, @@ -1756,7 +1754,7 @@ void Server::handle_6xB3x14_update_deck_during_setup(const string& data) { if (verify_error) { throw runtime_error(string_printf("invalid deck: -0x%" PRIX32, verify_error)); } - if (!(this->base()->behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) { + if (!(this->base()->data_index->behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) { this->ruler_server->replace_D1_D2_rarity_cards_with_Attack(entry.card_ids); } *this->base()->deck_entries[in_cmd.client_id] = in_cmd.entry; diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index 93863174..647cc7a3 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -52,20 +52,11 @@ class Server; -enum BehaviorFlag { - SKIP_DECK_VERIFY = 0x00000001, - IGNORE_CARD_COUNTS = 0x00000002, - SKIP_D1_D2_REPLACE = 0x00000004, - DISABLE_TIME_LIMITS = 0x00000008, - ENABLE_STATUS_MESSAGES = 0x00000010, -}; - class ServerBase : public std::enable_shared_from_this { public: ServerBase( std::shared_ptr lobby, std::shared_ptr data_index, - uint32_t behavior_flags, uint32_t random_seed); void init(); void reset(); @@ -81,7 +72,6 @@ public: std::weak_ptr lobby; std::shared_ptr data_index; - uint32_t behavior_flags; uint32_t random_seed; std::shared_ptr map_and_rules1; diff --git a/src/Main.cc b/src/Main.cc index 99cfb362..41d358ae 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -778,7 +778,7 @@ int main(int argc, char** argv) { case Behavior::SHOW_EP3_DATA: { config_log.info("Collecting Episode 3 data"); - Episode3::DataIndex index("system/ep3", true); + Episode3::DataIndex index("system/ep3", Episode3::BehaviorFlag::LOAD_CARD_TEXT); if (ep3_card_id == 0xFFFF) { auto map_ids = index.all_map_ids(); @@ -884,7 +884,8 @@ int main(int argc, char** argv) { state->load_bb_file("ItemRT.rel"))); config_log.info("Collecting Episode 3 data"); - state->ep3_data_index.reset(new Episode3::DataIndex("system/ep3")); + state->ep3_data_index.reset(new Episode3::DataIndex( + "system/ep3", state->ep3_behavior_flags)); config_log.info("Collecting quest metadata"); state->quest_index.reset(new QuestIndex("system/quests")); diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index ec4a6324..600928be 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -921,7 +921,7 @@ static void on_ep3_server_data_request(shared_ptr s, shared_ptrlog.info("Recreating Episode 3 server state"); } l->ep3_server_base = make_shared( - l, s->ep3_data_index, s->ep3_behavior_flags, l->random_seed); + l, s->ep3_data_index, l->random_seed); l->ep3_server_base->init(); if (s->ep3_behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES) { diff --git a/system/config.example.json b/system/config.example.json index 73f45e5b..ae80dfd0 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -259,6 +259,9 @@ // 0x00000008 => Disable overall and per-phase battle time limits, regardless // of the options chosen during battle setup // 0x00000010 => Enable debug messages in Episode 3 games and battles + // 0x00000020 => Load card text as well as card definitions (has no behavioral + // effects; this flag exists to be used internally when the + // --show-ep3-data option is given) "Episode3BehaviorFlags": 0x00000002, // Episode 3 card auction configuration. CardAuctionPoints specifies how many