mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
60db0e5ef9
This updates `fmt` to the latest version and moves to just being a copy of their repo to make updating easier (no editing their cmake / figuring out which files to minimally include). The motivation for this is now that we switched to C++ 20, there were a ton of deprecated function usages that is going away in future compiler versions. This gets rid of all those warnings.
253 lines
8.5 KiB
C++
253 lines
8.5 KiB
C++
#include "find_defpartgroup.h"
|
|
|
|
#include "common/goos/PrettyPrinter.h"
|
|
#include "common/util/BitUtils.h"
|
|
|
|
#include "decompiler/IR2/Form.h"
|
|
#include "decompiler/IR2/GenericElementMatcher.h"
|
|
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
|
#include "decompiler/util/data_decompile.h"
|
|
|
|
namespace decompiler {
|
|
|
|
namespace {
|
|
|
|
const goos::Object& car(const goos::Object* x) {
|
|
return x->as_pair()->car;
|
|
}
|
|
|
|
const goos::Object* cdr(const goos::Object* x) {
|
|
return &x->as_pair()->cdr;
|
|
}
|
|
|
|
void read_static_group_data(DecompiledDataElement* src,
|
|
const Env& env,
|
|
DefpartgroupElement::StaticInfo& group) {
|
|
auto lab = src->label();
|
|
// looks like:
|
|
/*
|
|
.type sparticle-launch-group
|
|
L81:
|
|
.word 0xbb80042
|
|
.word 0x405dc
|
|
.word L83
|
|
.word L82
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x47800000
|
|
L82:
|
|
*/
|
|
|
|
int word_idx = (lab.offset / 4) - 1;
|
|
auto& words = env.file->words_by_seg.at(lab.target_segment);
|
|
|
|
auto& first_word = words.at(word_idx++);
|
|
if (first_word.kind() != LinkedWord::TYPE_PTR ||
|
|
first_word.symbol_name() != "sparticle-launch-group") {
|
|
env.func->warnings.error_and_throw(
|
|
"Reference to sparticle-launch-group bad: invalid type pointer");
|
|
}
|
|
|
|
auto& word_1 = words.at(word_idx++);
|
|
s16 len = word_1.data & 0xffff;
|
|
group.duration = (word_1.data >> 16) & 0xffff;
|
|
auto& word_2 = words.at(word_idx++);
|
|
group.linger = word_2.data & 0xffff;
|
|
group.flags = (word_2.data >> 16) & 0xffff;
|
|
|
|
auto& string_word = words.at(word_idx++);
|
|
if (string_word.kind() != LinkedWord::PTR) {
|
|
env.func->warnings.error_and_throw(
|
|
"Reference to sparticle-launch-group bad: invalid name label");
|
|
}
|
|
group.name = env.file->get_goal_string_by_label(
|
|
env.file->get_label_by_name(env.file->get_label_name(string_word.label_id())));
|
|
|
|
auto& array_word = words.at(word_idx++);
|
|
if (array_word.kind() != LinkedWord::PTR) {
|
|
env.func->warnings.error_and_throw(
|
|
"Reference to sparticle-launch-group bad: invalid array label");
|
|
}
|
|
auto& array_lab = env.file->get_label_by_name(env.file->get_label_name(array_word.label_id()));
|
|
auto& array_words = env.file->words_by_seg.at(array_lab.target_segment);
|
|
int array_start_word_idx = array_lab.offset / 4;
|
|
group.elts.clear();
|
|
for (int i = 0; i < len; ++i) {
|
|
int item_idx = i * 8 + array_start_word_idx;
|
|
auto& item = group.elts.emplace_back();
|
|
item.part_id = array_words.at(item_idx + 0).data;
|
|
item.fade = *reinterpret_cast<float*>(&array_words.at(item_idx + 1).data);
|
|
item.falloff = *reinterpret_cast<float*>(&array_words.at(item_idx + 2).data);
|
|
item.flags = array_words.at(item_idx + 3).data & 0xffff;
|
|
item.period = (array_words.at(item_idx + 3).data >> 16) & 0xffff;
|
|
item.length = array_words.at(item_idx + 4).data & 0xffff;
|
|
item.offset = (array_words.at(item_idx + 4).data >> 16) & 0xffff;
|
|
item.hour_mask = array_words.at(item_idx + 5).data;
|
|
item.binding = array_words.at(item_idx + 6).data;
|
|
}
|
|
|
|
if (env.version != GameVersion::Jak1) {
|
|
// added fields in jak 2
|
|
for (int i = 0; i < 3; i++) {
|
|
auto& word = words.at(word_idx++);
|
|
if (word.kind() != LinkedWord::PLAIN_DATA) {
|
|
env.func->warnings.error_and_throw("Reference to sparticle-launch-group bad: invalid rot");
|
|
}
|
|
group.rot[i] = *reinterpret_cast<float*>(&word.data);
|
|
}
|
|
for (int i = 0; i < 3; i++) {
|
|
auto& word = words.at(word_idx++);
|
|
if (word.kind() != LinkedWord::PLAIN_DATA) {
|
|
env.func->warnings.error_and_throw(
|
|
"Reference to sparticle-launch-group bad: invalid scale");
|
|
}
|
|
group.scale[i] = *reinterpret_cast<float*>(&word.data);
|
|
}
|
|
}
|
|
|
|
word_idx = align4(word_idx);
|
|
for (int i = 0; i < 4; i++) {
|
|
auto& word = words.at(word_idx + i);
|
|
if (word.kind() != LinkedWord::PLAIN_DATA) {
|
|
env.func->warnings.error_and_throw("Reference to sparticle-launch-group bad: invalid bounds");
|
|
}
|
|
group.bounds[i] = *reinterpret_cast<float*>(&word.data);
|
|
}
|
|
word_idx += 4;
|
|
}
|
|
|
|
void read_static_part_data(DecompiledDataElement* src,
|
|
const Env& env,
|
|
DefpartElement::StaticInfo& part) {
|
|
auto lab = src->label();
|
|
// looks like:
|
|
/*
|
|
.type sparticle-launcher
|
|
L79:
|
|
.word 0x0
|
|
.word 0x0
|
|
.word L80
|
|
L80:
|
|
.word 0x1
|
|
.word 0x201200
|
|
.word 0x0
|
|
.word 0x0
|
|
.word 0x10006
|
|
.word 0x3dcccccd
|
|
.word 0x0
|
|
.word 0x3f800000
|
|
*/
|
|
|
|
int start_word_idx = (lab.offset / 4) - 1;
|
|
auto& words = env.file->words_by_seg.at(lab.target_segment);
|
|
|
|
auto& first_word = words.at(start_word_idx);
|
|
if (first_word.kind() != LinkedWord::TYPE_PTR ||
|
|
first_word.symbol_name() != "sparticle-launcher") {
|
|
env.func->warnings.error_and_throw("Reference to sparticle-launcher bad: invalid type pointer");
|
|
}
|
|
|
|
auto& empty1 = words.at(start_word_idx + 1);
|
|
auto& empty2 = words.at(start_word_idx + 2);
|
|
if (empty1.kind() != LinkedWord::PLAIN_DATA || empty1.data != 0 ||
|
|
empty2.kind() != LinkedWord::PLAIN_DATA || empty2.data != 0) {
|
|
env.func->warnings.error_and_throw("Reference to sparticle-launcher bad: accums not empty");
|
|
}
|
|
|
|
auto& array_word = words.at(start_word_idx + 3);
|
|
if (array_word.kind() != LinkedWord::PTR) {
|
|
env.func->warnings.error_and_throw("Reference to sparticle-launcher bad: invalid array label");
|
|
}
|
|
auto& array_lab = env.file->get_label_by_name(env.file->get_label_name(array_word.label_id()));
|
|
auto& array_words = env.file->words_by_seg.at(array_lab.target_segment);
|
|
int array_start_word_idx = array_lab.offset / 4;
|
|
part.fields.clear();
|
|
src->do_decomp(env, env.file);
|
|
auto obj = src->to_form(env);
|
|
obj = car(cdr(cdr(&obj)));
|
|
auto cur_field = cdr(&obj);
|
|
for (int i = 0; true; ++i) {
|
|
int field_idx = i * 4 + array_start_word_idx;
|
|
auto& item = part.fields.emplace_back();
|
|
item.field_id = array_words.at(field_idx + 0).data & 0xffff;
|
|
item.flags = (array_words.at(field_idx + 0).data >> 16) & 0xffff;
|
|
item.data.push_back(array_words.at(field_idx + 0));
|
|
item.data.push_back(array_words.at(field_idx + 1));
|
|
item.data.push_back(array_words.at(field_idx + 2));
|
|
item.data.push_back(array_words.at(field_idx + 3));
|
|
if (item.flags == 4) {
|
|
auto& fld = car(cur_field);
|
|
item.sound_spec = cdr(cdr(cdr(cdr(&fld))))->as_pair()->car;
|
|
}
|
|
item.userdata = car(cur_field);
|
|
if (item.is_sp_end(env.version)) {
|
|
// sp-end
|
|
break;
|
|
}
|
|
cur_field = cdr(cur_field);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void run_defpartgroup(Function& top_level_func) {
|
|
auto& env = top_level_func.ir2.env;
|
|
auto& pool = *top_level_func.ir2.form_pool;
|
|
if (!top_level_func.ir2.top_form) {
|
|
return;
|
|
}
|
|
top_level_func.ir2.top_form->apply_form([&](Form* form) {
|
|
for (auto& fe : form->elts()) {
|
|
auto as_set = dynamic_cast<SetFormFormElement*>(fe);
|
|
if (as_set) {
|
|
/* Looks something like this:
|
|
(set! (-> *part-group-id-table* 188) (new 'static 'sparticle-launch-group
|
|
*/
|
|
if (as_set->dst()->elts().size() != 1) {
|
|
continue;
|
|
}
|
|
auto dest = dynamic_cast<DerefElement*>(as_set->dst()->elts().at(0));
|
|
if (!dest)
|
|
continue;
|
|
if (dest->tokens().size() != 1)
|
|
continue;
|
|
if (dest->tokens().at(0).kind() != DerefToken::Kind::INTEGER_CONSTANT)
|
|
continue;
|
|
if (dest->base()->elts().size() != 1)
|
|
continue;
|
|
auto dest_base = dynamic_cast<SimpleExpressionElement*>(dest->base()->elts().at(0));
|
|
if (!dest_base || !dest_base->expr().is_identity() || dest_base->expr().args() < 1)
|
|
continue;
|
|
auto src = dynamic_cast<DecompiledDataElement*>(as_set->src()->elts().at(0));
|
|
if (!src)
|
|
continue;
|
|
auto& sym = dest_base->expr().get_arg(0);
|
|
if (!sym.is_sym_val())
|
|
continue;
|
|
|
|
int id = dest->tokens().at(0).int_constant();
|
|
if (sym.get_str() == "*part-group-id-table*") {
|
|
DefpartgroupElement::StaticInfo group;
|
|
read_static_group_data(src, env, group);
|
|
auto rewritten = pool.alloc_element<DefpartgroupElement>(group, id);
|
|
if (rewritten) {
|
|
fe = rewritten;
|
|
}
|
|
} else if (sym.get_str() == "*part-id-table*") {
|
|
DefpartElement::StaticInfo part;
|
|
read_static_part_data(src, env, part);
|
|
auto rewritten = pool.alloc_element<DefpartElement>(part, id);
|
|
if (rewritten) {
|
|
fe = rewritten;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} // namespace decompiler
|