#include "PSOGCObjectGraph.hh" #include "Text.hh" using namespace std; struct TObjectVTable { phosg::be_uint32_t unused_a1; phosg::be_uint32_t unused_a2; phosg::be_uint32_t destroy; phosg::be_uint32_t update; phosg::be_uint32_t render; phosg::be_uint32_t render_shadow; } __packed_ws__(TObjectVTable, 0x18); struct TObject { phosg::be_uint32_t type_name_addr; phosg::be_uint16_t flags; parray unused; phosg::be_uint32_t prev_sibling_addr; phosg::be_uint32_t next_sibling_addr; phosg::be_uint32_t parent_addr; phosg::be_uint32_t children_head_addr; phosg::be_uint32_t vtable_addr; } __packed_ws__(TObject, 0x1C); PSOGCObjectGraph::PSOGCObjectGraph(const string& memory_data, uint32_t root_address) { phosg::StringReader r(memory_data); this->root = this->parse_object_memo(r, root_address); } shared_ptr PSOGCObjectGraph::parse_vtable_memo(phosg::StringReader& r, uint32_t addr) { try { return this->all_vtables.at(addr); } catch (const out_of_range&) { } const auto& vt = r.pget(addr & 0x01FFFFFF); auto ret = this->all_vtables.emplace(addr, make_shared()).first->second; ret->address = addr; ret->destroy_addr = vt.destroy; ret->update_addr = vt.update; ret->render_addr = vt.render; ret->render_shadow_addr = vt.render_shadow; return ret; } shared_ptr PSOGCObjectGraph::parse_object_memo(phosg::StringReader& r, uint32_t addr) { try { return this->all_objects.at(addr); } catch (const out_of_range&) { } const auto& obj = r.pget(addr & 0x01FFFFFF); string type_name = r.pget_cstr(obj.type_name_addr & 0x01FFFFFF); auto ret = this->all_objects.emplace(addr, make_shared()).first->second; ret->address = addr; ret->flags = obj.flags; ret->type_name = std::move(type_name); ret->vtable = this->parse_vtable_memo(r, obj.vtable_addr); if (obj.parent_addr) { ret->parent = this->parse_object_memo(r, obj.parent_addr); } if (obj.children_head_addr) { uint32_t child_addr = obj.children_head_addr; while (child_addr) { ret->children.emplace_back(this->parse_object_memo(r, child_addr)); child_addr = r.pget(child_addr & 0x01FFFFFF).next_sibling_addr; } } return ret; } void PSOGCObjectGraph::print(FILE* stream) const { this->root->print(stream); } void PSOGCObjectGraph::Object::print(FILE* stream, size_t indent_level) const { for (size_t z = 0; z < indent_level; z++) { fputc(' ', stream); fputc(' ', stream); } phosg::fwrite_fmt(stream, "{} +{:04X} @ {:08X} (VT {:08X}: destroy={:08X} update={:08X} render={:08X} render_shadow={:08X})\n", this->type_name, this->flags, this->address, this->vtable->address, this->vtable->destroy_addr, this->vtable->update_addr, this->vtable->render_addr, this->vtable->render_shadow_addr); for (const auto& child : this->children) { child->print(stream, indent_level + 1); } }