Skip to content

Commit

Permalink
use SetDataTable files as map indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzziqersoftware committed Jan 21, 2024
1 parent fe1d5a8 commit e13b595
Show file tree
Hide file tree
Showing 82 changed files with 686 additions and 156 deletions.
9 changes: 1 addition & 8 deletions src/FileContentsCache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,13 @@ shared_ptr<const string> ThreadSafeFileCache::get(
const string& name, std::function<shared_ptr<const string>(const std::string&)> generate) {
try {
shared_lock g(this->lock);
auto ret = this->name_to_file.at(name);
if (!ret) {
throw cannot_open_file(name);
}
return ret;
return this->name_to_file.at(name);
} catch (const out_of_range&) {
unique_lock g(this->lock);
auto it = this->name_to_file.find(name);
if (it == this->name_to_file.end()) {
it = this->name_to_file.emplace(name, generate(name)).first;
}
if (!it->second) {
throw cannot_open_file(name);
}
return it->second;
}
}
102 changes: 54 additions & 48 deletions src/Lobby.cc
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,30 @@ shared_ptr<Map> Lobby::load_maps(
uint8_t difficulty,
uint8_t event,
uint32_t lobby_id,
shared_ptr<const SetDataTableBase> sdt,
function<shared_ptr<const string>(Version, const string&)> get_file_data,
shared_ptr<const Map::RareEnemyRates> rare_rates,
shared_ptr<PSOLFGEncryption> random_crypt,
const parray<le_uint32_t, 0x20>& variations) {
const parray<le_uint32_t, 0x20>& variations,
const PrefixedLogger* log) {
auto enemy_filenames = sdt->map_filenames_for_variations(variations, episode, mode, true);
auto object_filenames = sdt->map_filenames_for_variations(variations, episode, mode, false);
return Lobby::load_maps(enemy_filenames, object_filenames, version, episode, mode, difficulty, event, lobby_id, get_file_data, rare_rates, random_crypt, log);
}

shared_ptr<Map> Lobby::load_maps(
const vector<string>& enemy_filenames,
const vector<string>& object_filenames,
Version version,
Episode episode,
GameMode mode,
uint8_t difficulty,
uint8_t event,
uint32_t lobby_id,
function<shared_ptr<const string>(Version, const string&)> get_file_data,
shared_ptr<const Map::RareEnemyRates> rare_rates,
shared_ptr<PSOLFGEncryption> random_crypt,
const PrefixedLogger* log) {
auto map = make_shared<Map>(version, lobby_id, random_crypt);

// Don't load free-roam maps in Challenge mode, since players can't go to
Expand All @@ -303,58 +323,42 @@ shared_ptr<Map> Lobby::load_maps(
return map;
}

for (size_t floor = 0; floor < 0x10; floor++) {
auto enemy_filenames = map_filenames_for_variation(
version,
episode,
mode,
floor,
variations[floor * 2],
variations[floor * 2 + 1],
true);
if (!enemy_filenames.empty()) {
bool any_map_loaded = false;
for (const string& filename : enemy_filenames) {
auto map_data = get_file_data(version, filename);
if (map_data) {
map->add_enemies_from_map_data(
episode,
difficulty,
event,
floor,
map_data->data(),
map_data->size(),
rare_rates);
any_map_loaded = true;
break;
for (size_t floor = 0; floor < 0x12; floor++) {
const auto& floor_enemy_filename = enemy_filenames.at(floor);
if (!floor_enemy_filename.empty()) {
auto map_data = get_file_data(version, floor_enemy_filename);
if (map_data) {
map->add_enemies_from_map_data(
episode,
difficulty,
event,
floor,
map_data->data(),
map_data->size(),
rare_rates);
if (log) {
log->info("Loaded enemies map %s for floor %02zX", floor_enemy_filename.c_str(), floor);
}
} else if (log) {
log->info("Enemies map %s for floor %02zX cannot be used; skipping", floor_enemy_filename.c_str(), floor);
}
if (!any_map_loaded) {
throw runtime_error(string_printf("no enemy maps loaded for floor %zu", floor));
}
} else if (log) {
log->info("No enemies to load for floor %02zX", floor);
}

auto object_filenames = map_filenames_for_variation(
version,
episode,
mode,
floor,
variations[floor * 2],
variations[floor * 2 + 1],
false);
if (!object_filenames.empty()) {
bool any_map_loaded = false;
for (const string& filename : object_filenames) {
auto map_data = get_file_data(version, filename);
if (map_data) {
map->add_objects_from_map_data(floor, map_data->data(), map_data->size());
any_map_loaded = true;
break;
const auto& floor_object_filename = object_filenames.at(floor);
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());
if (log) {
log->info("Loaded objects map %s for floor %02zX", floor_object_filename.c_str(), floor);
}
} else if (log) {
log->info("Objects map %s for floor %02zX cannot be used; skipping", floor_object_filename.c_str(), floor);
}
if (!any_map_loaded) {
throw runtime_error(string_printf("no object maps loaded for floor %zu", floor));
}
} else if (log) {
log->info("No objects to load for floor %02zX", floor);
}
}

Expand Down Expand Up @@ -392,10 +396,12 @@ void Lobby::load_maps() {
this->difficulty,
this->event,
this->lobby_id,
s->set_data_table(this->base_version, this->episode, this->mode, this->difficulty),
bind(&ServerState::load_map_file, s.get(), placeholders::_1, placeholders::_2),
rare_rates,
this->random_crypt,
this->variations);
this->variations,
&this->log);

} else {
this->map = make_shared<Map>(this->base_version, this->lobby_id, this->random_crypt);
Expand Down
17 changes: 16 additions & 1 deletion src/Lobby.hh
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,25 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
uint8_t difficulty,
uint8_t event,
uint32_t lobby_id,
std::shared_ptr<const SetDataTableBase> sdt,
std::function<std::shared_ptr<const std::string>(Version, const std::string&)> get_file_data,
std::shared_ptr<const Map::RareEnemyRates> rare_rates,
std::shared_ptr<PSOLFGEncryption> random_crypt,
const parray<le_uint32_t, 0x20>& variations);
const parray<le_uint32_t, 0x20>& variations,
const PrefixedLogger* log = nullptr);
static std::shared_ptr<Map> load_maps(
const std::vector<std::string>& enemy_filenames,
const std::vector<std::string>& object_filenames,
Version version,
Episode episode,
GameMode mode,
uint8_t difficulty,
uint8_t event,
uint32_t lobby_id,
std::function<std::shared_ptr<const std::string>(Version, const std::string&)> get_file_data,
std::shared_ptr<const Map::RareEnemyRates> rare_rates,
std::shared_ptr<PSOLFGEncryption> random_crypt,
const PrefixedLogger* log = nullptr);
void load_maps();
void create_ep3_server();

Expand Down
193 changes: 192 additions & 1 deletion src/Main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,196 @@ Action a_disassemble_quest_map(
string result = Map::disassemble_quest_data(data.data(), data.size());
write_output_data(args, result.data(), result.size(), "txt");
});
Action a_disassemble_set_data_table(
"disassemble-set-data-table", "\
disassemble-set-data-table [INPUT-FILENAME]\n\
Show the contents of a SetDataTable.rel file. A version option is required.\n",
+[](Arguments& args) {
Version version = get_cli_version(args);
SetDataTable sdt(version, read_input_data(args));
string str = sdt.str();
write_output_data(args, str.data(), str.size(), "txt");
});
Action a_check_set_data_table(
"check-set-data-tables", nullptr, +[](Arguments&) {
ServerState s;
s.load_objects_and_upstream_dependents("set_data_tables");
static_game_data_log.min_level = LogLevel::DISABLED;

auto get_file_data = [&](Version version, const string& filename) -> shared_ptr<const string> {
try {
return s.load_map_file(version, filename);
} catch (const cannot_open_file&) {
return nullptr;
}
};

auto check_filenames = [&](Version version, const string& sdt_filename, const vector<string>& ns_filenames) -> string {
for (size_t z = 0; z < ns_filenames.size(); z++) {
const auto& ns_filename = ns_filenames[z];
auto data = get_file_data(version, ns_filename);
if (data) {
if (sdt_filename != ns_filename) {
string ns_filenames_str = join(ns_filenames, ", ");
return string_printf("SDT => %s, NS => [%s]", sdt_filename.c_str(), ns_filenames_str.c_str());
}
return "OK";
}
if (!data && (sdt_filename == ns_filename)) {
string ns_filenames_str = join(ns_filenames, ", ");
return string_printf("SDT => %s (missing)", sdt_filename.c_str());
}
}
if (ns_filenames.empty() && sdt_filename.empty()) {
return "OK (no files)";
} else if (ns_filenames.empty()) {
auto data = get_file_data(version, sdt_filename);
if (data) {
return string_printf("NS blank, SDT => %s", sdt_filename.c_str());
} else {
return string_printf("NS blank, SDT => %s (missing)", sdt_filename.c_str());
}
} else if (sdt_filename.empty()) {
string ns_filenames_str = join(ns_filenames, ", ");
return string_printf("SDT blank, NS => [%s] (all missing)", ns_filenames_str.c_str());
} else {
string ns_filenames_str = join(ns_filenames, ", ");
return string_printf("SDT => %s (missing), NS => [%s] (all missing)", sdt_filename.c_str(), ns_filenames_str.c_str());
}
};

size_t num_checks = 0;
size_t num_errors = 0;
auto check_table = [&](Version version) {
vector<Episode> episodes({Episode::EP1});
if (!is_v1_or_v2(version) || (version == Version::GC_NTE)) {
episodes.emplace_back(Episode::EP2);
if (is_v4(version)) {
episodes.emplace_back(Episode::EP4);
}
}

vector<GameMode> modes({GameMode::NORMAL});
if (!is_v1(version)) {
modes.emplace_back(GameMode::BATTLE);
modes.emplace_back(GameMode::CHALLENGE);
}
if (is_v4(version)) {
modes.emplace_back(GameMode::SOLO);
}

uint8_t max_difficulty = is_v1(version) ? 2 : 3;

for (Episode episode : episodes) {
for (GameMode mode : modes) {
for (uint8_t difficulty = 0; difficulty <= max_difficulty; difficulty++) {
auto sdt = s.set_data_table(version, episode, mode, difficulty);
auto ns_var_maxes = variation_maxes_deprecated(version, episode, (mode == GameMode::SOLO));
size_t num_floors;
if (episode == Episode::EP4) {
num_floors = 0x0B;
} else if (episode == Episode::EP2) {
num_floors = 0x10;
} else {
num_floors = 0x0F;
}
for (size_t floor = 0; floor < num_floors; floor++) {
auto sdt_var_avail = sdt->num_available_variations_for_floor(episode, floor);
auto sdt_var_maxes = sdt->num_free_roam_variations_for_floor(episode, mode == GameMode::SOLO, floor);
size_t sdt_var1_max_avail = sdt_var_avail.first - 1;
size_t sdt_var2_max_avail = sdt_var_avail.second - 1;
size_t sdt_var1_max = sdt_var_maxes.first - 1;
size_t sdt_var2_max = sdt_var_maxes.second - 1;
size_t ns_var1_max = ns_var_maxes[floor * 2];
size_t ns_var2_max = ns_var_maxes[floor * 2 + 1];
num_checks += 4;
if (sdt_var1_max > sdt_var1_max_avail) {
fprintf(stdout, "## %-8s %-10s %-10s %-10s %02zX VAR1:[SDT:%02zX SDTA:%02zX]\n",
name_for_enum(version),
name_for_episode(episode),
name_for_mode(mode),
name_for_difficulty(difficulty),
floor,
sdt_var1_max,
sdt_var1_max_avail);
num_errors++;
}
if (sdt_var2_max > sdt_var2_max_avail) {
fprintf(stdout, "## %-8s %-10s %-10s %-10s %02zX VAR2:[SDT:%02zX SDTA:%02zX]\n",
name_for_enum(version),
name_for_episode(episode),
name_for_mode(mode),
name_for_difficulty(difficulty),
floor,
sdt_var2_max,
sdt_var2_max_avail);
num_errors++;
}
if (sdt_var1_max < ns_var1_max) {
fprintf(stdout, "## %-8s %-10s %-10s %-10s %02zX VAR1:[SDT:%02zX NS:%02zX]\n",
name_for_enum(version),
name_for_episode(episode),
name_for_mode(mode),
name_for_difficulty(difficulty),
floor,
sdt_var1_max,
ns_var1_max);
num_errors++;
}
if (sdt_var2_max < ns_var2_max) {
fprintf(stdout, "## %-8s %-10s %-10s %-10s %02zX VAR2:[SDT:%02zX NS:%02zX]\n",
name_for_enum(version),
name_for_episode(episode),
name_for_mode(mode),
name_for_difficulty(difficulty),
floor,
sdt_var2_max,
ns_var2_max);
num_errors++;
}
for (size_t var1 = 0; var1 <= ns_var1_max; var1++) {
for (size_t var2 = 0; var2 <= ns_var2_max; var2++) {
auto sdt_enemy_filename = sdt->map_filename_for_variation(floor, var1, var2, episode, mode, true);
auto sdt_object_filename = sdt->map_filename_for_variation(floor, var1, var2, episode, mode, false);
auto ns_enemy_filenames = map_filenames_for_variation_deprecated(floor, var1, var2, version, episode, mode, true);
auto ns_object_filenames = map_filenames_for_variation_deprecated(floor, var1, var2, version, episode, mode, false);
string enemies_error = check_filenames(version, sdt_enemy_filename, ns_enemy_filenames);
string objects_error = check_filenames(version, sdt_object_filename, ns_object_filenames);
num_checks += 2;
num_errors += (enemies_error != "OK") + (objects_error != "OK");
fprintf(stdout, "%s %-8s %-10s %-10s %-10s %02zX %02zX %02zX E:[%s] O:[%s] E:%-30s O:%-30s\n",
((enemies_error != "OK") || (objects_error != "OK")) ? "##" : " ",
name_for_enum(version),
name_for_episode(episode),
name_for_mode(mode),
name_for_difficulty(difficulty),
floor,
var1,
var2,
enemies_error.c_str(),
objects_error.c_str(),
sdt_enemy_filename.c_str(),
sdt_object_filename.c_str());
}
}
}
}
}
}
};

check_table(Version::DC_NTE);
check_table(Version::DC_V1_11_2000_PROTOTYPE);
check_table(Version::DC_V1);
check_table(Version::DC_V2);
check_table(Version::PC_NTE);
check_table(Version::PC_V2);
check_table(Version::GC_NTE);
check_table(Version::GC_V3);
check_table(Version::XB_V3);
check_table(Version::BB_V4);
fprintf(stdout, "%zu/%zu errors\n", num_errors, num_checks);
});

Action a_assemble_quest_script(
"assemble-quest-script", "\
Expand Down Expand Up @@ -1883,14 +2073,15 @@ Action a_find_rare_enemy_seeds(
map = Lobby::load_maps(version, episode, difficulty, 0, 0, rare_rates, random_crypt, vq);

} else {
generate_variations(variations, random_crypt, version, episode, (mode == GameMode::SOLO));
generate_variations_deprecated(variations, random_crypt, version, episode, (mode == GameMode::SOLO));
map = Lobby::load_maps(
version,
episode,
mode,
difficulty,
0,
0,
s.set_data_table(version, episode, mode, difficulty),
bind(&ServerState::load_map_file, &s, placeholders::_1, placeholders::_2),
rare_rates,
random_crypt,
Expand Down
Loading

0 comments on commit e13b595

Please sign in to comment.