mirror of
https://github.com/open-goal/jak-project
synced 2026-05-31 01:16:12 -04:00
d/jak2: finish cty-guard-turret-button | race-h | height-map-h and a lot of rigid-body (#1957)
Also cleaned up `data_decompiler.cpp` to make it a lot less verbose to add a special case for an array field.
This commit is contained in:
@@ -456,6 +456,17 @@ goos::Object decomp_ref_to_inline_array_guess_size(
|
||||
// we expect that to be a label:
|
||||
ASSERT((field_location % 4) == 0);
|
||||
auto pointer_to_data = words.at(field_location / 4);
|
||||
|
||||
// inline-arrays can also be initialized as #f
|
||||
if (pointer_to_data.kind() == LinkedWord::SYM_PTR) {
|
||||
ASSERT_MSG(
|
||||
pointer_to_data.symbol_name() == "#f",
|
||||
fmt::format(
|
||||
"attempted to decompile an inline-array of '{}', but encounted a non `#f` symbol",
|
||||
array_elt_type.base_type()));
|
||||
return pretty_print::to_symbol("#f");
|
||||
}
|
||||
|
||||
ASSERT(pointer_to_data.kind() == LinkedWord::PTR);
|
||||
|
||||
// the data shouldn't have any labels in the middle of it, so we can find the end of the array
|
||||
@@ -522,146 +533,6 @@ goos::Object decomp_ref_to_inline_array_guess_size(
|
||||
return pretty_print::build_list(array_def);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Decompile the data field of ocean-near-indices, which is an (inline-array ocean-near-index).
|
||||
* This is like a C++ ocean_near_index*, meaning we don't know how long the array is.
|
||||
* We know all the data in a ocean_near_index is just integers, so we can guess that the end
|
||||
* of the array is just the location of the next label.
|
||||
* There's a chance that this will include some padding in the array and make it too long,
|
||||
* but there is no harm in that.
|
||||
*/
|
||||
goos::Object ocean_near_indices_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("ocean-near-index"), 32, version);
|
||||
}
|
||||
|
||||
goos::Object ocean_mid_masks_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("ocean-mid-mask"), 8, version);
|
||||
}
|
||||
|
||||
goos::Object sp_field_init_spec_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("sp-field-init-spec"), 16, version);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_vertex_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-vertex"), 16, version);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_poly_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-poly"), 8, version);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_poly_arr_jak2_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-poly"), 64, version);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_nav_control_arr_decompile(
|
||||
const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-control"), 288, version);
|
||||
}
|
||||
|
||||
goos::Object xz_height_map_data_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("vector4b"), 4, version);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_route_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("vector4ub"), 4, version);
|
||||
}
|
||||
|
||||
goos::Object sp_launch_grp_launcher_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("sparticle-group-item"), 32, version);
|
||||
}
|
||||
goos::Object probe_dir_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file,
|
||||
GameVersion version) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("vector"), 16, version);
|
||||
}
|
||||
|
||||
goos::Object decompile_sound_spec(const TypeSpec& type,
|
||||
const DecompilerLabel& label,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
@@ -811,6 +682,58 @@ goos::Object decompile_sound_spec(const TypeSpec& type,
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO - add a common game version
|
||||
const std::unordered_map<
|
||||
GameVersion,
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, ArrayFieldDecompMeta>>>
|
||||
array_field_decomp_special_cases = {
|
||||
{GameVersion::Jak1,
|
||||
/*!
|
||||
* Decompile the data field of ocean-near-indices, which is an (inline-array
|
||||
* ocean-near-index). This is like a C++ ocean_near_index*, meaning we don't know how long
|
||||
* the array is. We know all the data in a ocean_near_index is just integers, so we can
|
||||
* guess that the end of the array is just the location of the next label. There's a chance
|
||||
* that this will include some padding in the array and make it too long, but there is no
|
||||
* harm in that.
|
||||
*/
|
||||
{{"ocean-near-indices",
|
||||
{{"data", ArrayFieldDecompMeta(TypeSpec("ocean-near-index"), 32)}}},
|
||||
{"ocean-mid-masks", {{"data", ArrayFieldDecompMeta(TypeSpec("ocean-mid-mask"), 8)}}},
|
||||
{"sparticle-launcher",
|
||||
{{"init-specs", ArrayFieldDecompMeta(TypeSpec("sp-field-init-spec"), 16)}}},
|
||||
{"sparticle-launch-group",
|
||||
{{"launcher", ArrayFieldDecompMeta(TypeSpec("sparticle-group-item"), 32)}}},
|
||||
{"nav-mesh",
|
||||
{{"vertex", ArrayFieldDecompMeta(TypeSpec("nav-vertex"), 16)},
|
||||
{"poly", ArrayFieldDecompMeta(TypeSpec("nav-poly"), 8)},
|
||||
{"route", ArrayFieldDecompMeta(TypeSpec("vector4ub"), 4)}}},
|
||||
{"lightning-probe-vars", {{"probe-dirs", ArrayFieldDecompMeta(TypeSpec("vector"), 16)}}},
|
||||
{"ropebridge-tuning",
|
||||
{{"col-mesh-indexes",
|
||||
ArrayFieldDecompMeta(TypeSpec("uint8"),
|
||||
1,
|
||||
ArrayFieldDecompMeta::Kind::REF_TO_INTEGER_ARR)}}}}},
|
||||
{GameVersion::Jak2,
|
||||
{{"ocean-near-indices",
|
||||
{{"data", ArrayFieldDecompMeta(TypeSpec("ocean-near-index"), 32)}}},
|
||||
{"ocean-mid-masks", {{"data", ArrayFieldDecompMeta(TypeSpec("ocean-mid-mask"), 8)}}},
|
||||
{"sparticle-launcher",
|
||||
{{"init-specs", ArrayFieldDecompMeta(TypeSpec("sp-field-init-spec"), 16)}}},
|
||||
{"sparticle-launch-group",
|
||||
{{"launcher", ArrayFieldDecompMeta(TypeSpec("sparticle-group-item"), 32)}}},
|
||||
{"race-info",
|
||||
{{"turbo-pad-array", ArrayFieldDecompMeta(TypeSpec("race-turbo-pad"), 32)},
|
||||
{"racer-array", ArrayFieldDecompMeta(TypeSpec("race-racer-info"), 16)},
|
||||
{"decision-point-array", ArrayFieldDecompMeta(TypeSpec("race-decision-point"), 16)}}},
|
||||
{"xz-height-map",
|
||||
{{"data", ArrayFieldDecompMeta(TypeSpec("int8"),
|
||||
1,
|
||||
ArrayFieldDecompMeta::Kind::REF_TO_INTEGER_ARR)}}},
|
||||
{"lightning-probe-vars", {{"probe-dirs", ArrayFieldDecompMeta(TypeSpec("vector"), 16)}}},
|
||||
{"nav-mesh",
|
||||
{{"poly-array", ArrayFieldDecompMeta(TypeSpec("nav-poly"), 64)},
|
||||
{"nav-control-array", ArrayFieldDecompMeta(TypeSpec("nav-control"), 288)}}}}}};
|
||||
|
||||
goos::Object decompile_structure(const TypeSpec& type,
|
||||
const DecompilerLabel& label,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
@@ -1029,64 +952,29 @@ goos::Object decompile_structure(const TypeSpec& type,
|
||||
fmt::format("Dynamic value field {} in static data type {} not yet implemented",
|
||||
field.name(), actual_type.print()));
|
||||
} else {
|
||||
// TODO - this is getting a little unwieldly -- refactor this at some point
|
||||
if (field.name() == "data" && type.print() == "ocean-near-indices") {
|
||||
// first, get the label:
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), ocean_near_indices_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "data" && type.print() == "ocean-mid-masks") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), ocean_mid_masks_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "init-specs" && type.print() == "sparticle-launcher") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), sp_field_init_spec_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "vertex" && type.print() == "nav-mesh" &&
|
||||
file->version == GameVersion::Jak1) {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_vertex_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "poly" && type.print() == "nav-mesh" &&
|
||||
file->version == GameVersion::Jak1) {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_poly_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "poly-array" && type.print() == "nav-mesh" &&
|
||||
file->version == GameVersion::Jak2) {
|
||||
field_defs_out.emplace_back(field.name(), nav_mesh_poly_arr_jak2_decompile(
|
||||
obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "nav-control-array" && type.print() == "nav-mesh" &&
|
||||
file->version == GameVersion::Jak2) {
|
||||
field_defs_out.emplace_back(field.name(), nav_mesh_nav_control_arr_decompile(
|
||||
obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "data" && type.print() == "xz-height-map" &&
|
||||
file->version == GameVersion::Jak2) {
|
||||
field_defs_out.emplace_back(field.name(), xz_height_map_data_arr_decompile(
|
||||
obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "route" && type.print() == "nav-mesh" &&
|
||||
file->version == GameVersion::Jak1) {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_route_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "launcher" && type.print() == "sparticle-launch-group") {
|
||||
field_defs_out.emplace_back(field.name(), sp_launch_grp_launcher_decompile(
|
||||
obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else if (field.name() == "col-mesh-indexes" && type.print() == "ropebridge-tuning") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), decomp_ref_to_integer_array_guess_size(
|
||||
obj_words, labels, label.target_segment, field_start, ts, words,
|
||||
file, TypeSpec("uint8"), 1));
|
||||
} else if (field.name() == "probe-dirs" && type.print() == "lightning-probe-vars") {
|
||||
field_defs_out.emplace_back(field.name(),
|
||||
probe_dir_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file, version));
|
||||
} else {
|
||||
// array field special cases, uses the map initialized above!
|
||||
// check if there is a special case for this type+field+version combination
|
||||
if (file && array_field_decomp_special_cases.count(file->version) > 0 &&
|
||||
array_field_decomp_special_cases.at(file->version).count(type.print()) > 0 &&
|
||||
array_field_decomp_special_cases.at(file->version)
|
||||
.at(type.print())
|
||||
.count(field.name()) > 0) {
|
||||
// We have a special case, do the things
|
||||
const auto& metadata =
|
||||
array_field_decomp_special_cases.at(file->version).at(type.print()).at(field.name());
|
||||
if (metadata.kind == ArrayFieldDecompMeta::Kind::REF_TO_INLINE_ARR) {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(),
|
||||
decomp_ref_to_inline_array_guess_size(
|
||||
obj_words, labels, label.target_segment, field_start, ts, words, file,
|
||||
metadata.element_type, metadata.bytes_per_element, file->version));
|
||||
} else if (metadata.kind == ArrayFieldDecompMeta::Kind::REF_TO_INTEGER_ARR) {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), decomp_ref_to_integer_array_guess_size(
|
||||
obj_words, labels, label.target_segment, field_start, ts, words,
|
||||
file, metadata.element_type, metadata.bytes_per_element));
|
||||
}
|
||||
} else { // otherwise, it's a pointer array or plain data
|
||||
if (field.type().base_type() == "pointer") {
|
||||
if (obj_words.at(field_start / 4).kind() != LinkedWord::SYM_PTR) {
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user