construct supermaps on-demand instead of at startup
This commit is contained in:
+1
-1
@@ -2637,7 +2637,7 @@ Action a_load_maps_test(
|
||||
s->load_maps(false);
|
||||
|
||||
SuperMap::EfficiencyStats all_free_maps_eff;
|
||||
for (const auto& it : s->supermaps) {
|
||||
for (const auto& it : s->supermap_for_free_play_key) {
|
||||
auto episode = static_cast<Episode>((it.first >> 28) & 7);
|
||||
auto mode = static_cast<GameMode>((it.first >> 26) & 3);
|
||||
uint8_t difficulty = (it.first >> 24) & 3;
|
||||
|
||||
+1
-6
@@ -636,7 +636,7 @@ QuestIndex::QuestIndex(
|
||||
} else if (phosg::ends_with(filename, ".dlq")) {
|
||||
file_data = decode_dlq_data(phosg::load_file(file_path));
|
||||
filename.resize(filename.size() - 4);
|
||||
} else if (phosg::ends_with(filename, ".txt")) {
|
||||
} else if (phosg::ends_with(filename, ".bin.txt")) {
|
||||
string include_dir = phosg::dirname(file_path);
|
||||
file_data = assemble_quest_script(phosg::load_file(file_path), include_dir);
|
||||
filename.resize(filename.size() - 4);
|
||||
@@ -891,11 +891,6 @@ QuestIndex::QuestIndex(
|
||||
static_game_data_log.warning("(%s) Failed to index quest file: (%s)", basename.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
// Create supermaps for all quests that need them (all non-Ep3 quests)
|
||||
for (const auto& it : this->quests_by_number) {
|
||||
it.second->get_supermap(-1);
|
||||
}
|
||||
}
|
||||
|
||||
phosg::JSON QuestIndex::json() const {
|
||||
|
||||
+2
-2
@@ -2874,11 +2874,11 @@ opcodes_by_name_for_version(Version v) {
|
||||
if (!(def.flags & vf)) {
|
||||
continue;
|
||||
}
|
||||
if (def.name && !index.emplace(def.name, &def).second) {
|
||||
if (def.name && !index.emplace(phosg::tolower(def.name), &def).second) {
|
||||
throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
|
||||
}
|
||||
if (def.qedit_name) {
|
||||
string lower_qedit_name = phosg::tolower(def.qedit_name);
|
||||
string lower_qedit_name = phosg::tolower(phosg::tolower(def.qedit_name));
|
||||
if ((lower_qedit_name != def.name) && !index.emplace(lower_qedit_name, &def).second) {
|
||||
throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
|
||||
}
|
||||
|
||||
+71
-59
@@ -1567,8 +1567,8 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
|
||||
config_log.info("Loading free play map files");
|
||||
|
||||
unordered_map<uint64_t, shared_ptr<const MapFile>> map_file_for_source_hash;
|
||||
map<uint32_t, array<shared_ptr<const MapFile>, NUM_VERSIONS>> map_files;
|
||||
unordered_map<uint64_t, shared_ptr<const MapFile>> new_map_file_for_source_hash;
|
||||
map<uint32_t, array<shared_ptr<const MapFile>, NUM_VERSIONS>> new_map_files_for_free_play_key;
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
|
||||
for (Episode episode : episodes) {
|
||||
@@ -1592,7 +1592,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
auto variation_maxes = sdt->num_free_play_variations_for_floor(episode, mode == GameMode::SOLO, floor);
|
||||
for (size_t var_layout = 0; var_layout < variation_maxes.layout; var_layout++) {
|
||||
for (size_t var_entities = 0; var_entities < variation_maxes.entities; var_entities++) {
|
||||
uint32_t supermap_key = this->supermap_key(episode, mode, difficulty, floor, var_layout, var_entities);
|
||||
uint32_t free_play_key = this->free_play_key(episode, mode, difficulty, floor, var_layout, var_entities);
|
||||
|
||||
auto objects_filename = sdt->map_filename_for_variation(
|
||||
episode, mode, floor, var_layout, var_entities, SDT::FilenameType::OBJECT_SETS);
|
||||
@@ -1611,13 +1611,13 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
(events_data ? phosg::fnv1a64(*events_data) : 0));
|
||||
shared_ptr<const MapFile> map_file;
|
||||
try {
|
||||
map_file = map_file_for_source_hash.at(source_hash);
|
||||
map_file = new_map_file_for_source_hash.at(source_hash);
|
||||
} catch (const out_of_range&) {
|
||||
map_file = make_shared<MapFile>(floor, objects_data, enemies_data, events_data);
|
||||
if (map_file->source_hash() != source_hash) {
|
||||
throw logic_error("incorrect source hash");
|
||||
}
|
||||
map_file_for_source_hash.emplace(map_file->source_hash(), map_file);
|
||||
new_map_file_for_source_hash.emplace(map_file->source_hash(), map_file);
|
||||
}
|
||||
|
||||
// Uncomment for debugging
|
||||
@@ -1629,7 +1629,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
// floor,
|
||||
// var_layout,
|
||||
// var_entities,
|
||||
// supermap_key,
|
||||
// free_play_key,
|
||||
// map_file->source_hash(),
|
||||
// objects_filename.empty() ? "(none)" : objects_filename.c_str(),
|
||||
// objects_data ? "present" : "missing",
|
||||
@@ -1641,7 +1641,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
// events_data ? "present" : "missing",
|
||||
// map_file->count_events());
|
||||
|
||||
map_files[supermap_key].at(static_cast<size_t>(v)) = map_file;
|
||||
new_map_files_for_free_play_key[free_play_key].at(static_cast<size_t>(v)) = map_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1651,74 +1651,86 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
||||
}
|
||||
}
|
||||
|
||||
config_log.info("Constructing free play supermaps");
|
||||
|
||||
unordered_map<uint64_t, shared_ptr<const SuperMap>> supermap_for_source_hash_sum;
|
||||
unordered_map<uint32_t, shared_ptr<const SuperMap>> new_supermaps;
|
||||
for (const auto& it : map_files) {
|
||||
uint64_t source_hash_sum = 0;
|
||||
for (auto map_file : it.second) {
|
||||
source_hash_sum += map_file ? map_file->source_hash() : 0;
|
||||
}
|
||||
|
||||
Episode episode = static_cast<Episode>((it.first >> 28) & 7);
|
||||
// Uncomment for debugging
|
||||
// auto mode = static_cast<GameMode>((it.first >> 26) & 3);
|
||||
// uint8_t difficulty = (it.first >> 24) & 3;
|
||||
// uint8_t floor = (it.first >> 16) & 0xFF;
|
||||
// uint8_t layout = (it.first >> 8) & 0xFF;
|
||||
// uint8_t entities = (it.first >> 0) & 0xFF;
|
||||
// fprintf(stderr, "SuperMap for %s %s %s %02hhX %02hhX %02hhX (%08" PRIX32 "): %016" PRIX64 " from",
|
||||
// name_for_episode(episode),
|
||||
// name_for_mode(mode),
|
||||
// name_for_difficulty(difficulty),
|
||||
// floor,
|
||||
// layout,
|
||||
// entities,
|
||||
// it.first,
|
||||
// source_hash_sum);
|
||||
// for (const auto& map_file : it.second) {
|
||||
// if (map_file) {
|
||||
// fprintf(stderr, " %016" PRIX64, map_file->source_hash());
|
||||
// } else {
|
||||
// fprintf(stderr, " ----------------");
|
||||
// }
|
||||
// }
|
||||
// fputc('\n', stderr);
|
||||
|
||||
shared_ptr<const SuperMap> supermap;
|
||||
try {
|
||||
supermap = supermap_for_source_hash_sum.at(source_hash_sum);
|
||||
static_game_data_log.info("Linking existing free play supermap %016" PRIX64 " for key %08" PRIX32, source_hash_sum, it.first);
|
||||
} catch (const out_of_range&) {
|
||||
supermap = make_shared<SuperMap>(episode, it.second);
|
||||
supermap_for_source_hash_sum.emplace(source_hash_sum, supermap);
|
||||
static_game_data_log.info("Constructed free play supermap %016" PRIX64 " for key %08" PRIX32, source_hash_sum, it.first);
|
||||
}
|
||||
new_supermaps.emplace(it.first, supermap);
|
||||
}
|
||||
|
||||
auto set = [s = this->shared_from_this(), new_supermaps = std::move(new_supermaps)]() {
|
||||
s->supermaps = std::move(new_supermaps);
|
||||
auto set = [s = this->shared_from_this(),
|
||||
new_map_file_for_source_hash = std::move(new_map_file_for_source_hash),
|
||||
new_map_files_for_free_play_key = std::move(new_map_files_for_free_play_key)]() {
|
||||
s->map_file_for_source_hash = std::move(new_map_file_for_source_hash);
|
||||
s->map_files_for_free_play_key = std::move(new_map_files_for_free_play_key);
|
||||
s->supermap_for_source_hash_sum.clear();
|
||||
s->supermap_for_free_play_key.clear();
|
||||
};
|
||||
this->forward_or_call(from_non_event_thread, std::move(set));
|
||||
}
|
||||
|
||||
shared_ptr<const SuperMap> ServerState::get_free_play_supermap(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities) {
|
||||
uint32_t free_play_key = this->free_play_key(episode, mode, difficulty, floor, layout, entities);
|
||||
try {
|
||||
return this->supermap_for_free_play_key.at(free_play_key);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
const array<shared_ptr<const MapFile>, NUM_VERSIONS>* map_files;
|
||||
try {
|
||||
map_files = &this->map_files_for_free_play_key.at(free_play_key);
|
||||
} catch (const out_of_range&) {
|
||||
static_game_data_log.info("No maps exist for key %08" PRIX32 "; cannot construct supermap", free_play_key);
|
||||
this->supermap_for_free_play_key.emplace(free_play_key, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t source_hash_sum = 0;
|
||||
for (auto map_file : *map_files) {
|
||||
source_hash_sum += map_file ? map_file->source_hash() : 0;
|
||||
}
|
||||
|
||||
// Uncomment for debugging
|
||||
// fprintf(stderr, "SuperMap for %s %s %s %02hhX %02hhX %02hhX (%08" PRIX32 "): %016" PRIX64 " from",
|
||||
// name_for_episode(episode),
|
||||
// name_for_mode(mode),
|
||||
// name_for_difficulty(difficulty),
|
||||
// floor,
|
||||
// layout,
|
||||
// entities,
|
||||
// free_play_key,
|
||||
// source_hash_sum);
|
||||
// for (const auto& map_file : it.second) {
|
||||
// if (map_file) {
|
||||
// fprintf(stderr, " %016" PRIX64, map_file->source_hash());
|
||||
// } else {
|
||||
// fprintf(stderr, " ----------------");
|
||||
// }
|
||||
// }
|
||||
// fputc('\n', stderr);
|
||||
|
||||
shared_ptr<const SuperMap> supermap;
|
||||
try {
|
||||
supermap = this->supermap_for_source_hash_sum.at(source_hash_sum);
|
||||
static_game_data_log.info("Linking existing free play supermap %016" PRIX64 " for key %08" PRIX32, source_hash_sum, free_play_key);
|
||||
} catch (const out_of_range&) {
|
||||
supermap = make_shared<SuperMap>(episode, *map_files);
|
||||
this->supermap_for_source_hash_sum.emplace(source_hash_sum, supermap);
|
||||
static_game_data_log.info("Constructed free play supermap %016" PRIX64 " for key %08" PRIX32, source_hash_sum, free_play_key);
|
||||
}
|
||||
this->supermap_for_free_play_key.emplace(free_play_key, supermap);
|
||||
return supermap;
|
||||
}
|
||||
|
||||
vector<shared_ptr<const SuperMap>> ServerState::supermaps_for_variations(
|
||||
Episode episode,
|
||||
GameMode mode,
|
||||
uint8_t difficulty,
|
||||
const Variations& variations) const {
|
||||
const Variations& variations) {
|
||||
vector<shared_ptr<const SuperMap>> ret;
|
||||
for (size_t floor = 0; floor < 0x12; floor++) {
|
||||
Variations::Entry e;
|
||||
if (floor < variations.entries.size()) {
|
||||
e = variations.entries[floor];
|
||||
}
|
||||
ret.push_back(this->get_supermap(episode, mode, difficulty, floor, e.layout, e.entities));
|
||||
ret.push_back(this->get_free_play_supermap(episode, mode, difficulty, floor, e.layout, e.entities));
|
||||
if (ret.back()) {
|
||||
static_game_data_log.info("Using supermap %08" PRIX32 " for floor %02zX layout %" PRIX32 " entities %" PRIX32,
|
||||
this->supermap_key(episode, mode, difficulty, floor, e.layout, e.entities),
|
||||
this->free_play_key(episode, mode, difficulty, floor, e.layout, e.entities),
|
||||
floor, e.layout.load(), e.entities.load());
|
||||
} else {
|
||||
static_game_data_log.info("No supermap available for floor %02zX layout %" PRIX32 " entities %" PRIX32,
|
||||
|
||||
+8
-11
@@ -172,7 +172,10 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::shared_ptr<const FunctionCodeIndex> function_code_index;
|
||||
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
||||
std::shared_ptr<const PatchFileIndex> bb_patch_file_index;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<const SuperMap>> supermaps; // Keyed by supermap_key
|
||||
std::unordered_map<uint64_t, std::shared_ptr<const MapFile>> map_file_for_source_hash;
|
||||
std::map<uint32_t, std::array<std::shared_ptr<const MapFile>, NUM_VERSIONS>> map_files_for_free_play_key;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<const SuperMap>> supermap_for_source_hash_sum;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<const SuperMap>> supermap_for_free_play_key;
|
||||
std::shared_ptr<FileContentsCache> bb_stream_files_cache;
|
||||
std::shared_ptr<FileContentsCache> bb_system_cache;
|
||||
std::shared_ptr<FileContentsCache> gba_files_cache;
|
||||
@@ -403,7 +406,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::shared_ptr<PatchServer::Config> generate_patch_server_config(bool is_bb) const;
|
||||
void update_dependent_server_configs() const;
|
||||
|
||||
static constexpr uint32_t supermap_key(
|
||||
static constexpr uint32_t free_play_key(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities) {
|
||||
return (static_cast<uint32_t>(episode) << 28) |
|
||||
(static_cast<uint32_t>(mode) << 26) |
|
||||
@@ -412,19 +415,13 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
(static_cast<uint32_t>(layout) << 8) |
|
||||
(static_cast<uint32_t>(entities) << 0);
|
||||
}
|
||||
inline std::shared_ptr<const SuperMap> get_supermap(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities) const {
|
||||
try {
|
||||
return this->supermaps.at(this->supermap_key(episode, mode, difficulty, floor, layout, entities));
|
||||
} catch (const std::out_of_range&) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::shared_ptr<const SuperMap> get_free_play_supermap(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities);
|
||||
std::vector<std::shared_ptr<const SuperMap>> supermaps_for_variations(
|
||||
Episode episode,
|
||||
GameMode mode,
|
||||
uint8_t difficulty,
|
||||
const Variations& variations) const;
|
||||
const Variations& variations);
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user