Skip to content

Commit

Permalink
decompiler: defskelgroup macro detection for jak 3, fix art group d…
Browse files Browse the repository at this point in the history
…umping for jak 3 and some more decomp work (#3370)

- `transformq`
- `wind-work`
- `progress-static`
- `merc-vu1`
- `emerc-vu1`
- `merc`
- `emerc`
- `cloth-h`
- Most of `cloth`, not added to gsrc yet

Art group dumps were incorrect for Jak 3 because the master art group
fields were at different offsets.
  • Loading branch information
Hat-Kid authored Feb 11, 2024
1 parent 18903f0 commit a4e629e
Show file tree
Hide file tree
Showing 48 changed files with 13,902 additions and 2,533 deletions.
153 changes: 144 additions & 9 deletions decompiler/IR2/Form.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "decompiler/util/data_decompile.h"
#include "decompiler/util/sparticle_decompile.h"

#include "third-party/fmt/ranges.h"

namespace decompiler {

///////////////////
Expand Down Expand Up @@ -3065,6 +3067,120 @@ void DefskelgroupElement::get_modified_regs(RegSet& regs) const {
m_info.jgeo->get_modified_regs(regs);
}

goos::Object DefskelgroupElement::ClothParams::to_list(const std::string& ag_name,
const Env& env) const {
std::vector<goos::Object> result;
if (mesh != 0) {
// TODO use art element name for mesh
(void)ag_name;
// const auto& art = env.dts->art_group_info;
// if (art.find(ag_name) != art.end() && art.at(ag_name).find(mesh) != art.at(ag_name).end()) {
// auto name = art.at(ag_name).at(mesh);
// result.push_back(pretty_print::build_list(
// {pretty_print::to_symbol("mesh"), pretty_print::to_symbol(name)}));
// } else {
// result.push_back(pretty_print::build_list(
// {pretty_print::to_symbol("mesh"), pretty_print::to_symbol(std::to_string(mesh))}));
// }
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("mesh"), pretty_print::to_symbol(std::to_string(mesh))}));
}
if (gravity != 0.0f) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("gravity-constant"),
pretty_print::to_symbol(fmt::format("(meters {})", meters_to_string(gravity)))}));
}
if (wind != 0.0f) {
result.push_back(pretty_print::build_list({pretty_print::to_symbol("wind-constant"),
pretty_print::to_symbol(float_to_string(wind))}));
}
if (width != 0) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("cloth-width"), pretty_print::to_symbol(std::to_string(width))}));
}
if (sphere_constraints != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-sphere-constraints"),
pretty_print::to_symbol(std::to_string(sphere_constraints))}));
}
if (disc_constraints != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-disc-constraints"),
pretty_print::to_symbol(std::to_string(disc_constraints))}));
}
if (anchor_points != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-anchor-points"),
pretty_print::to_symbol(std::to_string(anchor_points))}));
}
if (flags != 0) {
auto bits = decompile_bitfield_enum_from_int(TypeSpec("cloth-flag"), env.dts->ts, flags);
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("flags"),
pretty_print::to_symbol(fmt::format("(cloth-flag {})", fmt::join(bits, " ")))}));
}
if (!tex_name.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name"), pretty_print::new_string(tex_name)}));
}
if (!tex_name2.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name2"), pretty_print::new_string(tex_name2)}));
}
if (!tex_name3.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name3"), pretty_print::new_string(tex_name3)}));
}
if (!alt_tex_name.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name"), pretty_print::new_string(alt_tex_name)}));
}
if (!alt_tex_name2.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name2"), pretty_print::new_string(alt_tex_name2)}));
}
if (!alt_tex_name3.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name3"), pretty_print::new_string(alt_tex_name3)}));
}
if (thickness != 0.0f) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("cloth-thickness"),
pretty_print::to_symbol(float_to_string(thickness))}));
}
if (xform != 0) {
result.push_back(pretty_print::build_list({pretty_print::to_symbol("initial-xform"),
pretty_print::to_symbol(std::to_string(xform))}));
}
if (drag != 0.0f) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("drag"), pretty_print::to_symbol(float_to_string(drag))}));
}
if (ball_collision_radius != 0.0f) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("ball-collision-radius"),
pretty_print::to_symbol(fmt::format(
"(meters {})", meters_to_string(ball_collision_radius)))}));
}
if (iterations != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-iterations"),
pretty_print::to_symbol(std::to_string(iterations))}));
}
if (timestep_freq != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("timestep-frequency"),
pretty_print::to_symbol(std::to_string(timestep_freq))}));
}
if (secret != 0) {
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, flags);
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("secret-disable"),
pretty_print::to_symbol(fmt::format("(game-secrets {})", fmt::join(bits, " ")))}));
}
return pretty_print::build_list(result);
}

goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("defskelgroup"));
Expand Down Expand Up @@ -3124,15 +3240,21 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
if (m_static_info.sort != 0) {
forms.push_back(pretty_print::to_symbol(fmt::format(":sort {}", m_static_info.sort)));
}
// jak 2 skelgroups seem to be using version 7
if (env.version != GameVersion::Jak1) {
if (m_static_info.version != 7) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
} else {
if (m_static_info.version != 6) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
switch (env.version) {
case GameVersion::Jak1:
if (m_static_info.version != 6) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
break;
case GameVersion::Jak2:
if (m_static_info.version != 7) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
break;
case GameVersion::Jak3:
if (m_static_info.version != 8) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
}
if (env.version != GameVersion::Jak1) {
if (m_static_info.origin_joint_index != 0) {
Expand All @@ -3147,6 +3269,19 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
forms.push_back(
pretty_print::to_symbol(fmt::format(":light-index {}", m_static_info.light_index)));
}
if (m_static_info.global_effects != 0) {
forms.push_back(
pretty_print::to_symbol(fmt::format(":global-effects {}", m_static_info.global_effects)));
}
if (!m_static_info.clothing.empty()) {
std::vector<goos::Object> cloth_list;
forms.push_back(pretty_print::to_symbol(":clothing"));
for (const auto& p : m_static_info.clothing) {
auto macro = p.to_list(m_static_info.art_group_name + "-ag", env);
cloth_list.push_back(macro);
}
forms.push_back(pretty_print::build_list(cloth_list));
}
}

return pretty_print::build_list(forms);
Expand Down
30 changes: 29 additions & 1 deletion decompiler/IR2/Form.h
Original file line number Diff line number Diff line change
Expand Up @@ -1687,8 +1687,33 @@ class DefstateElement : public FormElement {

class DefskelgroupElement : public FormElement {
public:
struct ClothParams {
u16 mesh;
float gravity;
float wind;
u16 width;
u16 sphere_constraints;
u16 disc_constraints;
u16 anchor_points;
u64 flags;
std::string tex_name;
std::string tex_name2;
std::string tex_name3;
std::string alt_tex_name;
std::string alt_tex_name2;
std::string alt_tex_name3;
float thickness;
u16 xform;
float drag;
float ball_collision_radius;
u8 iterations;
u8 timestep_freq;
u64 secret;

goos::Object to_list(const std::string& ag_name, const Env& env) const;
};
struct StaticInfo {
std::string name; // jak 2
std::string name; // jak 2/3
std::string art_group_name;
math::Vector4f bounds;
int max_lod;
Expand All @@ -1700,6 +1725,9 @@ class DefskelgroupElement : public FormElement {
s8 origin_joint_index;
s8 shadow_joint_index;
s8 light_index;
// jak 3
s8 global_effects;
std::vector<ClothParams> clothing;
};
struct Entry {
Form* mgeo = nullptr;
Expand Down
65 changes: 64 additions & 1 deletion decompiler/ObjectFile/ObjectFileDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,8 @@ void get_joint_info(ObjectFileDB& db, ObjectFileData& obj, JointGeo jg) {
}

void get_art_info(ObjectFileDB& db, ObjectFileData& obj) {
if (obj.obj_version == 4 || (obj.obj_version == 5 && obj.linked_data.segments == 1)) {
// jak 1/2
if (obj.obj_version == 4) {
const auto& words = obj.linked_data.words_by_seg.at(MAIN_SEGMENT);
if (words.at(0).kind() == LinkedWord::Kind::TYPE_PTR &&
words.at(0).symbol_name() == "art-group") {
Expand Down Expand Up @@ -961,6 +962,68 @@ void get_art_info(ObjectFileDB& db, ObjectFileData& obj) {
}
}
}
// jak 3
if (obj.obj_version == 5 && obj.linked_data.segments == 1) {
const auto& words = obj.linked_data.words_by_seg.at(MAIN_SEGMENT);
if (words.at(0).kind() == LinkedWord::Kind::TYPE_PTR &&
words.at(0).symbol_name() == "art-group") {
auto obj_unique_name = obj.to_unique_name();

// lg::print("art-group {}:\n", obj.to_unique_name());
auto name = obj.linked_data.get_goal_string_by_label(words.at(2).label_id());
int length = words.at(3).data;
// lg::print(" length: {}\n", length);
for (int i = 0; i < length; ++i) {
const auto& word = words.at(8 + i);
if (word.kind() == LinkedWord::Kind::SYM_PTR && word.symbol_name() == "#f") {
continue;
}
const auto& label = obj.linked_data.labels.at(word.label_id());
auto elt_name =
obj.linked_data.get_goal_string_by_label(words.at(label.offset / 4 + 1).label_id());
auto unique_name = elt_name;

auto ag_name = obj_unique_name;
int elt_index = i;
std::string elt_type = words.at(label.offset / 4 - 1).symbol_name();
auto& word_master_ag = words.at(label.offset / 4 + 4);
auto& word_master_idx = words.at(label.offset / 4 + 5);
if (word_master_ag.kind() == LinkedWord::Kind::PTR &&
word_master_idx.kind() == LinkedWord::Kind::PLAIN_DATA) {
ag_name = obj.linked_data.get_goal_string_by_label(word_master_ag.label_id()) + "-ag";
if (elt_type != "art-cloth-geo") {
elt_index = word_master_idx.data;
}
}

if (elt_type == "art-joint-geo") {
// the skeleton!
unique_name += "-jg";
JointGeo jg;
jg.offset = label.offset;
jg.name = unique_name;
jg.length = words.at(label.offset / 4 + 2).data;
get_joint_info(db, obj, jg);
} else if (elt_type == "merc-ctrl" || elt_type == "shadow-geo") {
// (maybe mesh-geo as well but that doesnt exist)
// the skin!
unique_name += "-mg";
} else if (elt_type == "art-joint-anim") {
// the animations!
unique_name += "-ja";
} else if (elt_type == "art-cloth-geo") {
// cloth geometry (jak 3)
unique_name += "-cg";
} else {
// the something idk!
throw std::runtime_error(
fmt::format("unknown art elt type {} in {}", elt_type, obj.to_unique_name()));
}
// lg::print(" {}: {} ({}) -> {} @ {}\n", i, elt_name, elt_type, unique_name, elt_index);
db.dts.add_art_group_elt(ag_name, unique_name, elt_index);
}
}
}
}
} // namespace

Expand Down
Loading

0 comments on commit a4e629e

Please sign in to comment.