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);
|
s->load_maps(false);
|
||||||
|
|
||||||
SuperMap::EfficiencyStats all_free_maps_eff;
|
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 episode = static_cast<Episode>((it.first >> 28) & 7);
|
||||||
auto mode = static_cast<GameMode>((it.first >> 26) & 3);
|
auto mode = static_cast<GameMode>((it.first >> 26) & 3);
|
||||||
uint8_t difficulty = (it.first >> 24) & 3;
|
uint8_t difficulty = (it.first >> 24) & 3;
|
||||||
|
|||||||
+1
-6
@@ -636,7 +636,7 @@ QuestIndex::QuestIndex(
|
|||||||
} else if (phosg::ends_with(filename, ".dlq")) {
|
} else if (phosg::ends_with(filename, ".dlq")) {
|
||||||
file_data = decode_dlq_data(phosg::load_file(file_path));
|
file_data = decode_dlq_data(phosg::load_file(file_path));
|
||||||
filename.resize(filename.size() - 4);
|
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);
|
string include_dir = phosg::dirname(file_path);
|
||||||
file_data = assemble_quest_script(phosg::load_file(file_path), include_dir);
|
file_data = assemble_quest_script(phosg::load_file(file_path), include_dir);
|
||||||
filename.resize(filename.size() - 4);
|
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());
|
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 {
|
phosg::JSON QuestIndex::json() const {
|
||||||
|
|||||||
+2
-2
@@ -2874,11 +2874,11 @@ opcodes_by_name_for_version(Version v) {
|
|||||||
if (!(def.flags & vf)) {
|
if (!(def.flags & vf)) {
|
||||||
continue;
|
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));
|
throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
|
||||||
}
|
}
|
||||||
if (def.qedit_name) {
|
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) {
|
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));
|
throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-34
@@ -1567,8 +1567,8 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
|
|
||||||
config_log.info("Loading free play map files");
|
config_log.info("Loading free play map files");
|
||||||
|
|
||||||
unordered_map<uint64_t, shared_ptr<const MapFile>> map_file_for_source_hash;
|
unordered_map<uint64_t, shared_ptr<const MapFile>> new_map_file_for_source_hash;
|
||||||
map<uint32_t, array<shared_ptr<const MapFile>, NUM_VERSIONS>> map_files;
|
map<uint32_t, array<shared_ptr<const MapFile>, NUM_VERSIONS>> new_map_files_for_free_play_key;
|
||||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||||
const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
|
const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
|
||||||
for (Episode episode : episodes) {
|
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);
|
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_layout = 0; var_layout < variation_maxes.layout; var_layout++) {
|
||||||
for (size_t var_entities = 0; var_entities < variation_maxes.entities; var_entities++) {
|
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(
|
auto objects_filename = sdt->map_filename_for_variation(
|
||||||
episode, mode, floor, var_layout, var_entities, SDT::FilenameType::OBJECT_SETS);
|
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));
|
(events_data ? phosg::fnv1a64(*events_data) : 0));
|
||||||
shared_ptr<const MapFile> map_file;
|
shared_ptr<const MapFile> map_file;
|
||||||
try {
|
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&) {
|
} catch (const out_of_range&) {
|
||||||
map_file = make_shared<MapFile>(floor, objects_data, enemies_data, events_data);
|
map_file = make_shared<MapFile>(floor, objects_data, enemies_data, events_data);
|
||||||
if (map_file->source_hash() != source_hash) {
|
if (map_file->source_hash() != source_hash) {
|
||||||
throw logic_error("incorrect 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
|
// Uncomment for debugging
|
||||||
@@ -1629,7 +1629,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
// floor,
|
// floor,
|
||||||
// var_layout,
|
// var_layout,
|
||||||
// var_entities,
|
// var_entities,
|
||||||
// supermap_key,
|
// free_play_key,
|
||||||
// map_file->source_hash(),
|
// map_file->source_hash(),
|
||||||
// objects_filename.empty() ? "(none)" : objects_filename.c_str(),
|
// objects_filename.empty() ? "(none)" : objects_filename.c_str(),
|
||||||
// objects_data ? "present" : "missing",
|
// objects_data ? "present" : "missing",
|
||||||
@@ -1641,7 +1641,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
// events_data ? "present" : "missing",
|
// events_data ? "present" : "missing",
|
||||||
// map_file->count_events());
|
// 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,23 +1651,40 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config_log.info("Constructing free play 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;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
uint64_t source_hash_sum = 0;
|
||||||
for (auto map_file : it.second) {
|
for (auto map_file : *map_files) {
|
||||||
source_hash_sum += map_file ? map_file->source_hash() : 0;
|
source_hash_sum += map_file ? map_file->source_hash() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Episode episode = static_cast<Episode>((it.first >> 28) & 7);
|
|
||||||
// Uncomment for debugging
|
// 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",
|
// fprintf(stderr, "SuperMap for %s %s %s %02hhX %02hhX %02hhX (%08" PRIX32 "): %016" PRIX64 " from",
|
||||||
// name_for_episode(episode),
|
// name_for_episode(episode),
|
||||||
// name_for_mode(mode),
|
// name_for_mode(mode),
|
||||||
@@ -1675,7 +1692,7 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
// floor,
|
// floor,
|
||||||
// layout,
|
// layout,
|
||||||
// entities,
|
// entities,
|
||||||
// it.first,
|
// free_play_key,
|
||||||
// source_hash_sum);
|
// source_hash_sum);
|
||||||
// for (const auto& map_file : it.second) {
|
// for (const auto& map_file : it.second) {
|
||||||
// if (map_file) {
|
// if (map_file) {
|
||||||
@@ -1688,37 +1705,32 @@ void ServerState::load_maps(bool from_non_event_thread) {
|
|||||||
|
|
||||||
shared_ptr<const SuperMap> supermap;
|
shared_ptr<const SuperMap> supermap;
|
||||||
try {
|
try {
|
||||||
supermap = supermap_for_source_hash_sum.at(source_hash_sum);
|
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, it.first);
|
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&) {
|
} catch (const out_of_range&) {
|
||||||
supermap = make_shared<SuperMap>(episode, it.second);
|
supermap = make_shared<SuperMap>(episode, *map_files);
|
||||||
supermap_for_source_hash_sum.emplace(source_hash_sum, supermap);
|
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, it.first);
|
static_game_data_log.info("Constructed free play supermap %016" PRIX64 " for key %08" PRIX32, source_hash_sum, free_play_key);
|
||||||
}
|
}
|
||||||
new_supermaps.emplace(it.first, supermap);
|
this->supermap_for_free_play_key.emplace(free_play_key, supermap);
|
||||||
}
|
return supermap;
|
||||||
|
|
||||||
auto set = [s = this->shared_from_this(), new_supermaps = std::move(new_supermaps)]() {
|
|
||||||
s->supermaps = std::move(new_supermaps);
|
|
||||||
};
|
|
||||||
this->forward_or_call(from_non_event_thread, std::move(set));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<shared_ptr<const SuperMap>> ServerState::supermaps_for_variations(
|
vector<shared_ptr<const SuperMap>> ServerState::supermaps_for_variations(
|
||||||
Episode episode,
|
Episode episode,
|
||||||
GameMode mode,
|
GameMode mode,
|
||||||
uint8_t difficulty,
|
uint8_t difficulty,
|
||||||
const Variations& variations) const {
|
const Variations& variations) {
|
||||||
vector<shared_ptr<const SuperMap>> ret;
|
vector<shared_ptr<const SuperMap>> ret;
|
||||||
for (size_t floor = 0; floor < 0x12; floor++) {
|
for (size_t floor = 0; floor < 0x12; floor++) {
|
||||||
Variations::Entry e;
|
Variations::Entry e;
|
||||||
if (floor < variations.entries.size()) {
|
if (floor < variations.entries.size()) {
|
||||||
e = variations.entries[floor];
|
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()) {
|
if (ret.back()) {
|
||||||
static_game_data_log.info("Using supermap %08" PRIX32 " for floor %02zX layout %" PRIX32 " entities %" PRIX32,
|
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());
|
floor, e.layout.load(), e.entities.load());
|
||||||
} else {
|
} else {
|
||||||
static_game_data_log.info("No supermap available for floor %02zX layout %" PRIX32 " entities %" PRIX32,
|
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 FunctionCodeIndex> function_code_index;
|
||||||
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
||||||
std::shared_ptr<const PatchFileIndex> bb_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_stream_files_cache;
|
||||||
std::shared_ptr<FileContentsCache> bb_system_cache;
|
std::shared_ptr<FileContentsCache> bb_system_cache;
|
||||||
std::shared_ptr<FileContentsCache> gba_files_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;
|
std::shared_ptr<PatchServer::Config> generate_patch_server_config(bool is_bb) const;
|
||||||
void update_dependent_server_configs() 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) {
|
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities) {
|
||||||
return (static_cast<uint32_t>(episode) << 28) |
|
return (static_cast<uint32_t>(episode) << 28) |
|
||||||
(static_cast<uint32_t>(mode) << 26) |
|
(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>(layout) << 8) |
|
||||||
(static_cast<uint32_t>(entities) << 0);
|
(static_cast<uint32_t>(entities) << 0);
|
||||||
}
|
}
|
||||||
inline std::shared_ptr<const SuperMap> get_supermap(
|
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) const {
|
Episode episode, GameMode mode, uint8_t difficulty, uint8_t floor, uint32_t layout, uint32_t entities);
|
||||||
try {
|
|
||||||
return this->supermaps.at(this->supermap_key(episode, mode, difficulty, floor, layout, entities));
|
|
||||||
} catch (const std::out_of_range&) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<std::shared_ptr<const SuperMap>> supermaps_for_variations(
|
std::vector<std::shared_ptr<const SuperMap>> supermaps_for_variations(
|
||||||
Episode episode,
|
Episode episode,
|
||||||
GameMode mode,
|
GameMode mode,
|
||||||
uint8_t difficulty,
|
uint8_t difficulty,
|
||||||
const Variations& variations) const;
|
const Variations& variations);
|
||||||
|
|
||||||
// The following functions may only be called from a non-event thread if they
|
// 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
|
// take a from_non_event_thread argument; any function that does not have this
|
||||||
|
|||||||
Reference in New Issue
Block a user