From 47bc37e80679df44cdaeeb55301a39b99bbe7012 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Wed, 16 Oct 2024 21:37:05 -0700 Subject: [PATCH] link map objects to constructor args instead of copying them --- src/Lobby.cc | 10 ++----- src/Main.cc | 2 +- src/Map.cc | 55 ++++++++++++++++++++++----------------- src/Map.hh | 24 ++++++++--------- src/ReceiveSubcommands.cc | 16 ++++++------ 5 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/Lobby.cc b/src/Lobby.cc index 361ae037..73312054 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -302,13 +302,7 @@ shared_ptr Lobby::load_maps( shared_ptr opt_rand_crypt, shared_ptr quest_dat_contents_decompressed) { auto map = make_shared(version, lobby_id, random_seed, opt_rand_crypt); - map->add_entities_from_quest_data( - episode, - difficulty, - event, - quest_dat_contents_decompressed->data(), - quest_dat_contents_decompressed->size(), - rare_rates); + map->add_entities_from_quest_data(episode, difficulty, event, quest_dat_contents_decompressed, rare_rates); return map; } @@ -396,7 +390,7 @@ shared_ptr Lobby::load_maps( if (!floor_object_filename.empty()) { auto map_data = get_file_data(version, floor_object_filename); if (map_data) { - map->add_objects_from_map_data(floor, map_data->data(), map_data->size()); + map->add_objects_from_map_data(floor, map_data); if (log) { log->info("Loaded objects map %s for floor %02zX", floor_object_filename.c_str(), floor); } diff --git a/src/Main.cc b/src/Main.cc index 3577a50a..82bd7eea 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -2401,7 +2401,7 @@ Action a_load_maps_test( fprintf(stderr, " [%s => ", objects_filename.c_str()); auto map_data = s->load_map_file(v, objects_filename); if (map_data) { - map->add_objects_from_map_data(floor, map_data->data(), map_data->size()); + map->add_objects_from_map_data(floor, map_data); fprintf(stderr, "%zu objects]", map->objects.size()); } else { fprintf(stderr, "__MISSING__]"); diff --git a/src/Map.cc b/src/Map.cc index 349dbf20..f6ecf3db 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -704,17 +704,25 @@ string Map::Event::str() const { } string Map::Object::str() const { - return phosg::string_printf("[Map::Object source %zX %04hX(%s) @%04hX p1=%g p456=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] floor=%02hhX item_drop_checked=%s]", - this->source_index, - this->base_type, - Map::name_for_object_type(this->base_type), - this->section, - this->param1, - this->param4, - this->param5, - this->param6, + return phosg::string_printf("[Map::Object floor %02hhX source %zX %04hX(%s) @%04hX:(%g %g %g)/(%04" PRIX32 " %04" PRIX32 " %04" PRIX32 ") +%04hX params [%g %g %g %08" PRIX32 " %08" PRIX32 " %08" PRIX32 "]]", this->floor, - this->item_drop_checked ? "true" : "false"); + this->source_index, + this->args->base_type.load(), + Map::name_for_object_type(this->args->base_type), + this->args->section.load(), + this->args->x.load(), + this->args->y.load(), + this->args->z.load(), + this->args->x_angle.load(), + this->args->y_angle.load(), + this->args->z_angle.load(), + this->args->group.load(), + this->args->param1.load(), + this->args->param2.load(), + this->args->param3.load(), + this->args->param4.load(), + this->args->param5.load(), + this->args->param6.load()); } Map::Map(Version version, uint32_t lobby_id, uint32_t rare_seed, std::shared_ptr opt_rand_crypt) @@ -729,7 +737,7 @@ void Map::clear() { this->rare_enemy_indexes.clear(); } -void Map::add_objects_from_map_data(uint8_t floor, const void* data, size_t size) { +void Map::add_objects_from_owned_map_data(uint8_t floor, const void* data, size_t size) { size_t entry_count = size / sizeof(ObjectEntry); if (size != entry_count * sizeof(ObjectEntry)) { throw runtime_error("data size is not a multiple of entry size"); @@ -739,17 +747,10 @@ void Map::add_objects_from_map_data(uint8_t floor, const void* data, size_t size for (size_t z = 0; z < entry_count; z++) { uint16_t object_id = this->objects.size(); this->objects.emplace_back(Object{ + .args = &objects[z], .source_index = z, .floor = floor, .object_id = object_id, - .base_type = objects[z].base_type, - .section = objects[z].section, - .group = objects[z].group, - .param1 = objects[z].param1, - .param3 = objects[z].param3, - .param4 = objects[z].param4, - .param5 = objects[z].param5, - .param6 = objects[z].param6, .game_flags = 0, .set_flags = 0, .item_drop_checked = false, @@ -759,6 +760,11 @@ void Map::add_objects_from_map_data(uint8_t floor, const void* data, size_t size } } +void Map::add_objects_from_map_data(uint8_t floor, std::shared_ptr data) { + this->link_owned_data(data); + this->add_objects_from_owned_map_data(floor, data->data(), data->size()); +} + bool Map::check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate) { if (default_is_rare) { return true; @@ -1597,12 +1603,13 @@ void Map::add_entities_from_quest_data( Episode episode, uint8_t difficulty, uint8_t event, - const void* data, - size_t size, + std::shared_ptr data, std::shared_ptr rare_rates) { - auto all_floor_sections = this->collect_quest_map_data_sections(data, size); + this->link_owned_data(data); - phosg::StringReader r(data, size); + auto all_floor_sections = this->collect_quest_map_data_sections(data->data(), data->size()); + + phosg::StringReader r(*data); shared_ptr random_state; for (size_t floor = 0; floor < all_floor_sections.size(); floor++) { const auto& floor_sections = all_floor_sections[floor]; @@ -1612,7 +1619,7 @@ void Map::add_entities_from_quest_data( if (header.data_size % sizeof(ObjectEntry)) { throw runtime_error("quest layout object section size is not a multiple of object entry size"); } - this->add_objects_from_map_data(floor, r.pgetv(floor_sections.objects + sizeof(header), header.data_size), header.data_size); + this->add_objects_from_owned_map_data(floor, r.pgetv(floor_sections.objects + sizeof(header), header.data_size), header.data_size); } if ((floor_sections.wave_events != 0xFFFFFFFF) && diff --git a/src/Map.hh b/src/Map.hh index 24e09f96..38b35451 100644 --- a/src/Map.hh +++ b/src/Map.hh @@ -51,9 +51,9 @@ struct Map { /* 1C */ le_uint32_t x_angle; /* 20 */ le_uint32_t y_angle; /* 24 */ le_uint32_t z_angle; - /* 28 */ le_float param1; // If <= 0, this is a specialized box, and the specialization is in param4/5/6 + /* 28 */ le_float param1; // Boxes: if <= 0, this is a specialized box, and the specialization is in param4/5/6 /* 2C */ le_float param2; - /* 30 */ le_float param3; + /* 30 */ le_float param3; // Boxes: if == 0, the item should be varied by difficulty and area /* 34 */ le_uint32_t param4; /* 38 */ le_uint32_t param5; /* 3C */ le_uint32_t param6; @@ -211,17 +211,10 @@ struct Map { struct Object { // TODO: Add more fields in here if we ever care about them. Currently we // only care about boxes with fixed item drops. + const ObjectEntry* args; size_t source_index; uint8_t floor; uint16_t object_id; - uint16_t base_type; - uint16_t section; - uint16_t group; - float param1; // If <= 0, this is a specialized box, and the specialization is in param4/5/6 - float param3; // If == 0, the item should be varied by difficulty and area - uint32_t param4; - uint32_t param5; - uint32_t param6; uint16_t game_flags; // Technically set_flags shouldn't be part of the Object struct, but all // object entries always generate exactly one object, so we store it here. @@ -305,7 +298,12 @@ struct Map { void clear(); - void add_objects_from_map_data(uint8_t floor, const void* data, size_t size); + inline void link_owned_data(std::shared_ptr data) { + this->linked_data.emplace(data); + } + + void add_objects_from_owned_map_data(uint8_t floor, const void* data, size_t size); + void add_objects_from_map_data(uint8_t floor, std::shared_ptr data); bool check_and_log_rare_enemy(bool default_is_rare, uint32_t rare_rate); void add_enemy( @@ -359,8 +357,7 @@ struct Map { Episode episode, uint8_t difficulty, uint8_t event, - const void* data, - size_t size, + std::shared_ptr data, std::shared_ptr rare_rates = Map::DEFAULT_RARE_ENEMIES); const Enemy& find_enemy(uint16_t enemy_id) const; @@ -380,6 +377,7 @@ struct Map { phosg::PrefixedLogger log; Version version; uint32_t rare_seed; + std::unordered_set> linked_data; std::shared_ptr opt_rand_crypt; std::vector objects; std::vector enemies; diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index a78da37e..d15e51c3 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -2579,26 +2579,26 @@ DropReconcileResult reconcile_drop_request_with_map( if (map) { map_object = &map->objects.at(cmd.entity_id); log.info("Drop check for K-%hX %c %s", - map_object->object_id, res.ignore_def ? 'G' : 'S', Map::name_for_object_type(map_object->base_type)); + map_object->object_id, res.ignore_def ? 'G' : 'S', Map::name_for_object_type(map_object->args->base_type)); if (cmd.floor != map_object->floor) { log.warning("Floor %02hhX from command does not match object\'s expected floor %02hhX", cmd.floor, map_object->floor); } if (is_v1_or_v2(version) && (version != Version::GC_NTE)) { // V1 and V2 don't have 6xA2, so we can't get ignore_def or the object // parameters from the client on those versions - cmd.param3 = map_object->param3; - cmd.param4 = map_object->param4; - cmd.param5 = map_object->param5; - cmd.param6 = map_object->param6; + cmd.param3 = map_object->args->param3; + cmd.param4 = map_object->args->param4; + cmd.param5 = map_object->args->param5; + cmd.param6 = map_object->args->param6; } - bool object_ignore_def = (map_object->param1 > 0.0); + bool object_ignore_def = (map_object->args->param1 > 0.0); if (res.ignore_def != object_ignore_def) { log.warning("ignore_def value %s from command does not match object\'s expected ignore_def %s (from p1=%g)", - res.ignore_def ? "true" : "false", object_ignore_def ? "true" : "false", map_object->param1); + res.ignore_def ? "true" : "false", object_ignore_def ? "true" : "false", map_object->args->param1.load()); } if (config.check_flag(Client::Flag::DEBUG_ENABLED)) { send_text_message_printf(client_channel, "$C5K-%hX %c %s", - map_object->object_id, res.ignore_def ? 'G' : 'S', Map::name_for_object_type(map_object->base_type)); + map_object->object_id, res.ignore_def ? 'G' : 'S', Map::name_for_object_type(map_object->args->base_type)); } }