/* by korenkonder GitHub/GitLab: korenkonder */ #include "pvpp.hpp" #include "f2/struct.hpp" #include "io/path.hpp" #include "io/stream.hpp" #include "hash.hpp" #include "str_utils.hpp" static void pvpp_a3da_read(pvpp_a3da* a3d, stream& s); static void pvpp_chara_read(pvpp_chara* chr, stream& s); static void pvpp_chara_effect_read(pvpp_chara_effect* chr_eff, stream& s); static void pvpp_chara_effect_a3da_read(pvpp_chara_effect_a3da* chr_pv_eff, stream& s); static void pvpp_chara_item_read(pvpp_chara_item* chr_itm, stream& s); static void pvpp_effect_read(pvpp_effect* eff, stream& s); static void pvpp_glitter_read(pvpp_glitter* glt, stream& s); static void pvpp_motion_read(pvpp_motion* mot, stream& s); static void pvpp_object_set_read(pvpp_object_set* objset, stream& s); static void pvpp_read_inner(pvpp* pp, stream& s); pvpp::pvpp() : ready() { } pvpp::~pvpp() { } void pvpp::read(const char* path) { if (!path) return; char* path_pvpp = str_utils_add(path, ".pvpp"); if (path_check_file_exists(path_pvpp)) { stream s; s.open(path_pvpp, "rb"); if (s.io.stream) pvpp_read_inner(this, s); } free(path_pvpp); } void pvpp::read(const wchar_t* path) { if (!path) return; wchar_t* path_pvpp = str_utils_add(path, L".pvpp"); if (path_check_file_exists(path_pvpp)) { stream s; s.open(path_pvpp, L"rb"); if (s.io.stream) pvpp_read_inner(this, s); } free(path_pvpp); } void pvpp::read(const void* data, size_t size) { if (!data || !size) return; stream s; s.open(data, size); pvpp_read_inner(this, s); } bool pvpp::load_file(void* data, const char* path, const char* file, uint32_t hash) { size_t file_len = utf8_length(file); const char* t = strrchr(file, '.'); if (t) file_len = t - file; std::string s = path + std::string(file, file_len); pvpp* pp = (pvpp*)data; pp->read(s.c_str()); return pp->ready; } pvpp_a3da::pvpp_a3da() : hash(hash_murmurhash_empty) { } pvpp_a3da::~pvpp_a3da() { } pvpp_chara::pvpp_chara() : chara_effect_init() { } pvpp_chara::~pvpp_chara() { } pvpp_chara_effect::pvpp_chara_effect() : base_chara(), chara_index() { } pvpp_chara_effect::~pvpp_chara_effect() { } pvpp_chara_effect_a3da::pvpp_chara_effect_a3da() : has_object_set(), u00(), u01(), u02(), u03(), u04(), u05(), u06(), u07() { } pvpp_chara_effect_a3da::~pvpp_chara_effect_a3da() { } pvpp_chara_item::pvpp_chara_item() : u18() { } pvpp_chara_item::~pvpp_chara_item() { } pvpp_effect::pvpp_effect() : chara_index() { } pvpp_effect::~pvpp_effect() { } pvpp_glitter::pvpp_glitter() : unk2() { } pvpp_glitter::~pvpp_glitter() { } pvpp_motion::pvpp_motion() : hash(hash_murmurhash_empty) { } pvpp_motion::~pvpp_motion() { } pvpp_object_set::pvpp_object_set() : hash(hash_murmurhash_empty) { } pvpp_object_set::~pvpp_object_set() { } static void pvpp_a3da_read(pvpp_a3da* a3d, stream& s) { a3d->name = s.read_string_null_terminated_offset(s.read_offset_x()); a3d->hash = s.read_uint32_t_reverse_endianness(); s.align_read(0x08); } static void pvpp_chara_read(pvpp_chara* chr, stream& s) { int8_t u00 = s.read_int8_t(); int8_t u01 = s.read_int8_t(); int8_t motion_count = s.read_int8_t(); int8_t a3da_count = s.read_int8_t(); int8_t item_count = s.read_int8_t(); int8_t u05 = s.read_int8_t(); int8_t glitter_count = s.read_int8_t(); int8_t u07 = s.read_int8_t(); size_t chr_eff_offset = s.read_offset_x(); size_t motion_offset = s.read_offset_x(); size_t a3da_offset = s.read_offset_x(); size_t item_offset = s.read_offset_x(); size_t glitter_offset = s.read_offset_x(); size_t o30 = s.read_offset_x(); chr->chara_effect_init = false; if (chr_eff_offset) { s.position_push(chr_eff_offset, SEEK_SET); pvpp_chara_effect_read(&chr->chara_effect, s); chr->chara_effect_init = true; s.position_pop(); } chr->motion.resize(motion_count); s.position_push(motion_offset, SEEK_SET); for (pvpp_motion& i : chr->motion) { s.position_push(s.read_offset_x(), SEEK_SET); pvpp_motion_read(&i, s); s.position_pop(); } s.position_pop(); chr->a3da.resize(a3da_count); s.position_push(a3da_offset, SEEK_SET); for (pvpp_a3da& i : chr->a3da) pvpp_a3da_read(&i, s); s.position_pop(); chr->item.resize(item_count); s.position_push(item_offset, SEEK_SET); for (pvpp_chara_item& i : chr->item) pvpp_chara_item_read(&i, s); s.position_pop(); chr->glitter.resize(glitter_count); s.position_push(glitter_offset, SEEK_SET); for (pvpp_glitter& i : chr->glitter) pvpp_glitter_read(&i, s); s.position_pop(); } static void pvpp_chara_effect_read(pvpp_chara_effect* chr_eff, stream& s) { chr_eff->base_chara = (pvpp_chara_type)s.read_uint8_t(); int8_t pv_effects_count = s.read_int8_t(); chr_eff->chara_index = (pvpp_chara_index)s.read_uint8_t(); size_t pv_effects_offstet = s.read_offset_x(); chr_eff->effect_a3da.resize(pv_effects_count); s.position_push(pv_effects_offstet, SEEK_SET); for (pvpp_chara_effect_a3da& i : chr_eff->effect_a3da) pvpp_chara_effect_a3da_read(&i, s); s.position_pop(); } static void pvpp_chara_effect_a3da_read(pvpp_chara_effect_a3da* chr_eff_a3da, stream& s) { chr_eff_a3da->u00 = s.read_uint8_t(); chr_eff_a3da->u01 = s.read_uint8_t(); chr_eff_a3da->u02 = s.read_uint8_t(); chr_eff_a3da->u03 = s.read_uint8_t(); chr_eff_a3da->u04 = s.read_uint8_t(); chr_eff_a3da->u05 = s.read_uint8_t(); chr_eff_a3da->u06 = s.read_uint8_t(); chr_eff_a3da->u07 = s.read_uint8_t(); size_t a3da_offset = s.read_offset_x(); size_t source_a3da_offset = s.read_offset_x(); s.position_push(a3da_offset, SEEK_SET); pvpp_a3da_read(&chr_eff_a3da->a3da, s); s.position_pop(); chr_eff_a3da->has_object_set = false; if (source_a3da_offset) { s.position_push(source_a3da_offset, SEEK_SET); pvpp_object_set_read(&chr_eff_a3da->object_set, s); chr_eff_a3da->has_object_set = true; s.position_pop(); } } static void pvpp_chara_item_read(pvpp_chara_item* chr_itm, stream& s) { int8_t a3das_count = s.read_int8_t(); size_t a3das_offset = s.read_offset_x(); size_t bone_offset = s.read_offset_x(); chr_itm->u18.x = s.read_float_t_reverse_endianness(); chr_itm->u18.y = s.read_float_t_reverse_endianness(); chr_itm->u18.z = s.read_float_t_reverse_endianness(); chr_itm->u18.w = s.read_float_t_reverse_endianness(); chr_itm->a3da.resize(a3das_count); s.position_push(a3das_offset, SEEK_SET); for (pvpp_a3da& i : chr_itm->a3da) pvpp_a3da_read(&i, s); s.position_pop(); chr_itm->bone = s.read_string_null_terminated_offset(bone_offset); } static void pvpp_effect_read(pvpp_effect* eff, stream& s) { int8_t a3das_count = s.read_int8_t(); int8_t glitters_count = s.read_int8_t(); eff->chara_index = (pvpp_chara_type)s.read_uint8_t(); int64_t a3das_offset = s.read_offset_x(); int64_t glitters_offset = s.read_offset_x(); eff->a3da.resize(a3das_count); s.position_push(a3das_offset, SEEK_SET); for (pvpp_a3da& i : eff->a3da) pvpp_a3da_read(&i, s); s.position_pop(); eff->glitter.resize(glitters_count); s.position_push(glitters_offset, SEEK_SET); for (pvpp_glitter& i : eff->glitter) pvpp_glitter_read(&i, s); s.position_pop(); } static void pvpp_glitter_read(pvpp_glitter* glt, stream& s) { glt->name = s.read_string_null_terminated_offset(s.read_offset_x()); glt->unk1 = s.read_string_null_terminated_offset(s.read_offset_x()); glt->unk2 = s.read_uint8_t() ? true : false; s.align_read(0x08); } static void pvpp_motion_read(pvpp_motion* mot, stream& s) { mot->name = s.read_string_null_terminated_offset(s.read_offset_x()); mot->hash = s.read_uint32_t_reverse_endianness(); s.align_read(0x08); } static void pvpp_object_set_read(pvpp_object_set* objset, stream& s) { objset->name = s.read_string_null_terminated_offset(s.read_offset_x()); objset->hash = s.read_uint32_t_reverse_endianness(); s.align_read(0x08); } static void pvpp_read_inner(pvpp* pp, stream& s) { f2_struct st; st.read(s); if (st.header.signature != reverse_endianness_uint32_t('PVPP') || !st.data.data()) return; stream s_pvpp; s_pvpp.open(st.data); s_pvpp.is_big_endian = st.header.use_big_endian; s_pvpp.read_uint32_t_reverse_endianness(); int8_t chara_count = s_pvpp.read_int8_t(); int64_t effect_offset = s_pvpp.read_offset_x(); int64_t chara_offset = s_pvpp.read_offset_x(); s_pvpp.read_offset_x(); pp->chara.resize(chara_count); s_pvpp.position_push(chara_offset, SEEK_SET); for (pvpp_chara& i : pp->chara) pvpp_chara_read(&i, s_pvpp); s_pvpp.position_pop(); s_pvpp.position_push( effect_offset, SEEK_SET); s_pvpp.read_uint8_t(); int8_t efffect_count = s_pvpp.read_int8_t(); effect_offset = s_pvpp.read_offset_x(); s_pvpp.position_pop(); pp->effect.resize(efffect_count); s_pvpp.position_push(effect_offset, SEEK_SET); for (pvpp_effect& i : pp->effect) pvpp_effect_read(&i, s_pvpp); s_pvpp.position_pop(); pp->ready = true; }