diff --git a/DataSpec/DNACommon/DNACommon.hpp b/DataSpec/DNACommon/DNACommon.hpp index 89073fb42..8018c0fea 100644 --- a/DataSpec/DNACommon/DNACommon.hpp +++ b/DataSpec/DNACommon/DNACommon.hpp @@ -73,6 +73,7 @@ public: } UniqueID32() = default; + UniqueID32(Athena::io::IStreamReader& reader) {read(reader);} UniqueID32(const char* hexStr) { char copy[9]; @@ -111,6 +112,7 @@ public: } UniqueID64() = default; + UniqueID64(Athena::io::IStreamReader& reader) {read(reader);} UniqueID64(const char* hexStr) { char copy[17]; diff --git a/DataSpec/DNACommon/MAPA.hpp b/DataSpec/DNACommon/MAPA.hpp index ceb4c151f..9dd5a2d60 100644 --- a/DataSpec/DNACommon/MAPA.hpp +++ b/DataSpec/DNACommon/MAPA.hpp @@ -1,4 +1,192 @@ #ifndef __DNACOMMON_MAPA_HPP__ #define __DNACOMMON_MAPA_HPP__ +#include "DNACommon.hpp" +#include "GX.hpp" + +namespace Retro +{ +namespace DNAMAPA +{ + +template +bool ReadMAPAToBlender(HECL::BlenderConnection& conn, + const MAPA& mapa, + const HECL::ProjectPath& outPath, + PAKRouter& pakRouter, + const typename PAKRouter::EntryType& entry, + bool force) +{ + /* Rename MAPA for consistency */ + HECL::ProjectPath mapaPath(outPath.getParentPath(), _S("!map.blend")); + if (!force && mapaPath.getPathType() == HECL::ProjectPath::PT_FILE) + return true; + + if (!conn.createBlend(mapaPath, HECL::BlenderConnection::TypeMapArea)) + return false; + HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); + + os << "import bpy, bmesh\n" + "from mathutils import Matrix\n" + "\n" + "bpy.types.Object.retro_mappable_type = bpy.props.IntProperty(name='Retro: MAPA object type', default=-1)\n" + "bpy.types.Object.retro_mappable_unk = bpy.props.IntProperty(name='Retro: MAPA object unk')\n" + "bpy.types.Object.retro_mappable_sclyid = bpy.props.StringProperty(name='Retro: MAPA object SCLY ID')\n" + "\n" + "# Clear Scene\n" + "for ob in bpy.data.objects:\n" + " bpy.context.scene.objects.unlink(ob)\n" + " bpy.data.objects.remove(ob)\n" + "\n" + "def add_triangle(bm, verts):\n" + " verts = [bm.verts[vi] for vi in verts]\n" + " face = bm.faces.get(verts)\n" + " if face:\n" + " face = face.copy()\n" + " bm.verts.ensure_lookup_table()\n" + " face.normal_flip()\n" + " else:\n" + " bm.faces.new(verts)\n" + "\n" + "def add_border(bm, verts):\n" + " verts = [bm.verts[vi] for vi in verts]\n" + " edge = bm.edges.get(verts)\n" + " edge.seam = True\n" + "\n"; + + os.format("bpy.context.scene.name = 'MAPA_%s'\n", + entry.id.toString().c_str()); + + /* Add empties representing MappableObjects */ + int moIdx = 0; + for (const typename MAPA::MappableObject& mo : mapa.mappableObjects) + { + os.format("obj = bpy.data.objects.new('MAPOBJ_%02d', None)\n" + "bpy.context.scene.objects.link(obj)\n" + "obj.retro_mappable_type = %d\n" + "obj.retro_mappable_unk = %d\n" + "obj.retro_mappable_sclyid = '%08X'\n" + "mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n" + "mtxd = mtx.decompose()\n" + "obj.rotation_mode = 'QUATERNION'\n" + "obj.location = mtxd[0]\n" + "obj.rotation_quaternion = mtxd[1]\n" + "obj.scale = mtxd[2]\n", + moIdx, mo.type, mo.unknown1, mo.sclyId, + mo.transformMtx[0].vec[0], mo.transformMtx[0].vec[1], mo.transformMtx[0].vec[2], mo.transformMtx[0].vec[3], + mo.transformMtx[1].vec[0], mo.transformMtx[1].vec[1], mo.transformMtx[1].vec[2], mo.transformMtx[1].vec[3], + mo.transformMtx[2].vec[0], mo.transformMtx[2].vec[1], mo.transformMtx[2].vec[2], mo.transformMtx[2].vec[3]); + ++moIdx; + } + + os << "# Begin bmesh\n" + "bm = bmesh.new()\n" + "\n"; + + /* Read in verts */ + for (const atVec3f& vert : mapa.vertices) + os.format("bm.verts.new((%f,%f,%f))\n", + vert.vec[0], vert.vec[1], vert.vec[2]); + os << "bm.verts.ensure_lookup_table()\n"; + + /* Read in surfaces */ + for (const typename MAPA::Surface& surf : mapa.surfaces) + { + for (const typename MAPA::Surface::Primitive& prim : surf.primitives) + { + auto iit = prim.indices.cbegin(); + + /* 3 Prim Verts to start */ + int c = 0; + unsigned int primVerts[3] = + { + *iit++, + *iit++, + *iit++ + }; + + if (GX::Primitive(prim.type) == GX::TRIANGLESTRIP) + { + atUint8 flip = 0; + for (int v=0 ; v= prim.indexCount - 3); + + /* Advance one prim vert */ + if (peek) + primVerts[c%3] = *iit; + else + primVerts[c%3] = *iit++; + ++c; + } + } + else if (GX::Primitive(prim.type) == GX::TRIANGLES) + { + for (int v=0 ; v= prim.indexCount) + break; + + /* Advance 3 Prim Verts */ + for (int pv=0 ; pv<3 ; ++pv) + primVerts[pv] = *iit++; + } + } + } + + for (const typename MAPA::Surface::Border& border : surf.borders) + { + auto iit = border.indices.cbegin(); + for (int i=0 ; i= m_sz) + if (m_pos > m_sz) LogDNACommon.report(LogVisor::FatalError, "PAK stream cursor overrun"); } atUint64 position() const {return m_pos;} @@ -309,6 +309,43 @@ public: progress(++count / bridgesSz); ++bridgeIdx; } + + /* TEMP: CSV dump */ + FILE* fp = HECL::Fopen(_S("/home/jacko/Desktop/mp_res.txt"), _S("w")); + for (const auto& entry : m_uniqueEntries) + { + const EntryType* ent = entry.second.second; + fprintf(fp, "%s\t0x%s\t\t", ent->type.toString().c_str(), entry.first.toString().c_str()); + switch (ent->unique.m_type) + { + case UniqueResult::UNIQUE_NOTFOUND: + case UniqueResult::UNIQUE_PAK: + { + const HECL::ProjectPath& pakPath = m_bridgePaths[entry.second.first].first; + fprintf(fp, _S("%s\n"), pakPath.getLastComponent()); + break; + } + case UniqueResult::UNIQUE_LEVEL: + fprintf(fp, _S("%s\n"), ent->unique.m_levelName->c_str()); + break; + case UniqueResult::UNIQUE_AREA: + fprintf(fp, _S("%s/%s\n"), ent->unique.m_levelName->c_str(), ent->unique.m_areaName->c_str()); + break; + case UniqueResult::UNIQUE_LAYER: + fprintf(fp, _S("%s/%s/%s\n"), ent->unique.m_levelName->c_str(), ent->unique.m_areaName->c_str(), ent->unique.m_layerName->c_str()); + break; + default: + fprintf(fp, "\n"); + break; + } + } + fprintf(fp, "\n"); + for (const auto& entry : m_sharedEntries) + { + const EntryType* ent = entry.second.second; + fprintf(fp, "%s\t0x%s\t\t\n", ent->type.toString().c_str(), entry.first.toString().c_str()); + } + fclose(fp); } void enterPAKBridge(const BRIDGETYPE& pakBridge) @@ -505,23 +542,33 @@ public: float fsz = sz; for (unsigned w=0 ; countm_idMap) + for (const auto& item : m_pak->m_firstEntries) { - ResExtractor extractor = BRIDGETYPE::LookupExtractor(*item.second); + ResExtractor extractor = BRIDGETYPE::LookupExtractor(*item); if (extractor.weight != w) continue; - std::string bestName = getBestEntryName(*item.second); + std::string bestName = getBestEntryName(*item); HECL::SystemStringView bestNameView(bestName); float thisFac = ++count / fsz; progress(bestNameView.sys_str().c_str(), thisFac); - HECL::ProjectPath working = getWorking(item.second, extractor); + /* TODO: Position after extracted item */ + HECL::ProjectPath cooked = getCooked(item); + if (force || cooked.getPathType() == HECL::ProjectPath::PT_NONE) + { + PAKEntryReadStream s = item->beginReadStream(*m_node); + FILE* fout = HECL::Fopen(cooked.getAbsolutePath().c_str(), _S("wb")); + fwrite(s.data(), 1, s.length(), fout); + fclose(fout); + } + + HECL::ProjectPath working = getWorking(item, extractor); if (extractor.func_a) /* Doesn't need PAKRouter access */ { if (force || working.getPathType() == HECL::ProjectPath::PT_NONE) { - PAKEntryReadStream s = item.second->beginReadStream(*m_node); + PAKEntryReadStream s = item->beginReadStream(*m_node); extractor.func_a(s, working); } } @@ -529,25 +576,14 @@ public: { if (force || working.getPathType() == HECL::ProjectPath::PT_NONE) { - PAKEntryReadStream s = item.second->beginReadStream(*m_node); - extractor.func_b(m_dataSpec, s, working, *this, *item.second, force, + PAKEntryReadStream s = item->beginReadStream(*m_node); + extractor.func_b(m_dataSpec, s, working, *this, *item, force, [&progress, thisFac](const HECL::SystemChar* update) { progress(update, thisFac); }); } } - - /* Extract original cooked copy AFTER working so timestamps make - * the original a valid cached item */ - HECL::ProjectPath cooked = getCooked(item.second); - if (force || cooked.getPathType() == HECL::ProjectPath::PT_NONE) - { - PAKEntryReadStream s = item.second->beginReadStream(*m_node); - FILE* fout = HECL::Fopen(cooked.getAbsolutePath().c_str(), _S("wb")); - fwrite(s.data(), 1, s.length(), fout); - fclose(fout); - } } } diff --git a/DataSpec/DNAMP1/DNAMP1.cpp b/DataSpec/DNAMP1/DNAMP1.cpp index d1aed438d..fa72fd243 100644 --- a/DataSpec/DNAMP1/DNAMP1.cpp +++ b/DataSpec/DNAMP1/DNAMP1.cpp @@ -9,6 +9,7 @@ #include "CMDL.hpp" #include "ANCS.hpp" #include "MREA.hpp" +#include "MAPA.hpp" namespace Retro { @@ -77,9 +78,11 @@ void PAKBridge::build() { Level& level = m_levelDeps[entry.id]; - PAKEntryReadStream rs = entry.beginReadStream(m_node); MLVL mlvl; - mlvl.read(rs); + { + PAKEntryReadStream rs = entry.beginReadStream(m_node); + mlvl.read(rs); + } #if HECL_UCS2 level.name = HECL::UTF8ToWide(m_pak.bestEntryName(entry)); #else @@ -88,6 +91,19 @@ void PAKBridge::build() level.areas.reserve(mlvl.areaCount); unsigned layerIdx = 0; + /* Make MAPW available to lookup MAPAs */ + const PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap); + std::vector mapw; + if (worldMapEnt) + { + PAKEntryReadStream rs = worldMapEnt->beginReadStream(m_node); + rs.seek(8, Athena::Current); + atUint32 areaCount = rs.readUint32Big(); + mapw.reserve(areaCount); + for (atUint32 i=0 ; ibeginReadStream(m_node); - areaName.read(rs); + { + PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node); + areaName.read(rs); + } areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0); /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (areaDeps.name.size() && iswblank(areaDeps.name.back())) + while (areaDeps.name.size() && iswspace(areaDeps.name.back())) areaDeps.name.pop_back(); #else - while (areaDeps.name.size() && isblank(areaDeps.name.back())) + while (areaDeps.name.size() && isspace(areaDeps.name.back())) areaDeps.name.pop_back(); #endif } @@ -120,7 +138,7 @@ void PAKBridge::build() #endif } HECL::SystemChar num[16]; - HECL::SNPrintf(num, 16, _S("%02u "), ai++); + HECL::SNPrintf(num, 16, _S("%02u "), ai); areaDeps.name = num + areaDeps.name; areaDeps.layers.reserve(area.depLayerCount-1); @@ -133,10 +151,10 @@ void PAKBridge::build() layer.active = layerFlags.flags >> (l-1) & 0x1; /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (layer.name.size() && iswblank(layer.name.back())) + while (layer.name.size() && iswspace(layer.name.back())) layer.name.pop_back(); #else - while (layer.name.size() && isblank(layer.name.back())) + while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif HECL::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); @@ -146,10 +164,13 @@ void PAKBridge::build() for (; r ai) + areaDeps.resources.emplace(mapw[ai]); + ++ai; } } } @@ -198,6 +219,8 @@ ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry) return {nullptr, MLVL::Extract, {_S(".blend")}, 3}; case SBIG('MREA'): return {nullptr, MREA::Extract, {_S(".blend")}, 4}; + case SBIG('MAPA'): + return {nullptr, MAPA::Extract, {_S(".blend")}, 4}; } return {}; } diff --git a/DataSpec/DNAMP1/MAPA.hpp b/DataSpec/DNAMP1/MAPA.hpp index 85fc3f237..44d3a606a 100644 --- a/DataSpec/DNAMP1/MAPA.hpp +++ b/DataSpec/DNAMP1/MAPA.hpp @@ -3,7 +3,9 @@ #include -#include "../DNACommon/DNACommon.hpp" +#include "../DNACommon/PAK.hpp" +#include "../DNACommon/MAPA.hpp" +#include "DNAMP1.hpp" namespace Retro { @@ -25,14 +27,36 @@ struct MAPA : BigDNA struct MappableObject : BigDNA { DECL_DNA - Value type; + enum Type : atUint32 + { + MOBlueDoor = 0, + MOShieldDoor = 1, + MOIceDoor = 2, + MOWaveDoor = 3, + MOPlasmaDoor = 4, + MOBigDoor1 = 5, + MOBigDoor2 = 6, + MOIceDoorCeiling = 7, + MOIceDoorFloor = 8, + MOWaveDoorCeiling = 9, + MOWaveDoorFloor = 10, + MOIceDoorFloor2 = 13, + MOWaveDoorFloor2 = 14, + MODownArrowYellow = 27, /* Maintenance Tunnel */ + MOUpArrowYellow = 28, /* Phazon Processing Center */ + MODownArrowGreen = 29, /* Elevator A */ + MOUpArrowGreen = 30, /* Elite Control Access */ + MODownArrowRed = 31, /* Elevator B */ + MOUpArrowRed = 32, /* Fungal Hall Access */ + MOTransportLift = 33, + MOSaveStation = 34, + MOMissileStation = 37 + }; + Value type; Value unknown1; - Value unknown2; - Value id; + Value sclyId; Seek seek1; - Value transform1; - Value transform2; - Value transform3; + Value transformMtx[3]; Seek seek2; }; Vector mappableObjects; @@ -42,9 +66,9 @@ struct MAPA : BigDNA { DECL_DNA Value normal; - Value center; - Value start; - Value end; + Value centroid; + Value polyOff; + Value edgeOff; }; Vector surfaceHeaders; @@ -58,7 +82,7 @@ struct MAPA : BigDNA DECL_DNA Value type; Value indexCount; - Vector indices; + Vector indices; Align<4> align; }; Vector primitives; @@ -67,13 +91,27 @@ struct MAPA : BigDNA { DECL_DNA Value indexCount; - Vector indices; + Vector indices; Align<4> align; }; Vector borders; }; Vector surfaces; + + static bool Extract(const SpecBase& dataSpec, + PAKEntryReadStream& rs, + const HECL::ProjectPath& outPath, + PAKRouter& pakRouter, + const PAK::Entry& entry, + bool force, + std::function fileChanged) + { + MAPA mapa; + mapa.read(rs); + HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); + return DNAMAPA::ReadMAPAToBlender(conn, mapa, outPath, pakRouter, entry, force); + } }; } } diff --git a/DataSpec/DNAMP1/MLVL.hpp b/DataSpec/DNAMP1/MLVL.hpp index d9294a5c1..839c923ac 100644 --- a/DataSpec/DNAMP1/MLVL.hpp +++ b/DataSpec/DNAMP1/MLVL.hpp @@ -116,6 +116,9 @@ struct MLVL : BigYAML { MLVL mlvl; mlvl.read(rs); + FILE* fp = HECL::Fopen(outPath.getWithExtension(_S(".yaml"), true).getAbsolutePath().c_str(), _S("w")); + mlvl.toYAMLFile(fp); + fclose(fp); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); return DNAMLVL::ReadMLVLToBlender(conn, mlvl, outPath, pakRouter, entry, force, fileChanged); diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp index 0a2370f50..edeabf6a7 100644 --- a/DataSpec/DNAMP1/MREA.cpp +++ b/DataSpec/DNAMP1/MREA.cpp @@ -46,13 +46,18 @@ bool MREA::Extract(const SpecBase& dataSpec, using RigPair = std::pair; RigPair dummy(nullptr, nullptr); + /* Rename MREA for consistency */ + HECL::ProjectPath mreaPath(outPath.getParentPath(), _S("!area.blend")); + if (!force && mreaPath.getPathType() == HECL::ProjectPath::PT_FILE) + return true; + /* Do extract */ Header head; head.read(rs); rs.seekAlign32(); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); - if (!conn.createBlend(outPath, HECL::BlenderConnection::TypeArea)) + if (!conn.createBlend(mreaPath, HECL::BlenderConnection::TypeArea)) return false; /* Open Py Stream and read sections */ diff --git a/DataSpec/DNAMP1/PAK.cpp b/DataSpec/DNAMP1/PAK.cpp index c12605445..d9947a35d 100644 --- a/DataSpec/DNAMP1/PAK.cpp +++ b/DataSpec/DNAMP1/PAK.cpp @@ -27,6 +27,8 @@ void PAK::read(Athena::io::IStreamReader& reader) atUint32 count = reader.readUint32Big(); m_entries.clear(); m_entries.reserve(count); + m_firstEntries.clear(); + m_firstEntries.reserve(count); m_idMap.clear(); m_idMap.reserve(count); for (atUint32 e=0 ; e m_nameEntries; std::vector m_entries; + std::vector m_firstEntries; std::unordered_map m_idMap; std::unordered_map m_nameMap; diff --git a/DataSpec/DNAMP2/DNAMP2.cpp b/DataSpec/DNAMP2/DNAMP2.cpp index 3c5d31855..264b1ef97 100644 --- a/DataSpec/DNAMP2/DNAMP2.cpp +++ b/DataSpec/DNAMP2/DNAMP2.cpp @@ -74,9 +74,11 @@ void PAKBridge::build() { Level& level = m_levelDeps[entry.id]; - PAKEntryReadStream rs = entry.beginReadStream(m_node); MLVL mlvl; - mlvl.read(rs); + { + PAKEntryReadStream rs = entry.beginReadStream(m_node); + mlvl.read(rs); + } #if HECL_UCS2 level.name = HECL::UTF8ToWide(m_pak.bestEntryName(entry)); #else @@ -85,6 +87,19 @@ void PAKBridge::build() level.areas.reserve(mlvl.areaCount); unsigned layerIdx = 0; + /* Make MAPW available to lookup MAPAs */ + const DNAMP1::PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap); + std::vector mapw; + if (worldMapEnt) + { + PAKEntryReadStream rs = worldMapEnt->beginReadStream(m_node); + rs.seek(8, Athena::Current); + atUint32 areaCount = rs.readUint32Big(); + mapw.reserve(areaCount); + for (atUint32 i=0 ; ibeginReadStream(m_node); - areaName.read(rs); + { + PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node); + areaName.read(rs); + } areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0); /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (areaDeps.name.size() && iswblank(areaDeps.name.back())) + while (areaDeps.name.size() && iswspace(areaDeps.name.back())) areaDeps.name.pop_back(); #else - while (areaDeps.name.size() && isblank(areaDeps.name.back())) + while (areaDeps.name.size() && isspace(areaDeps.name.back())) areaDeps.name.pop_back(); #endif } @@ -125,7 +142,7 @@ void PAKBridge::build() } } HECL::SystemChar num[16]; - HECL::SNPrintf(num, 16, _S("%02u "), ai++); + HECL::SNPrintf(num, 16, _S("%02u "), ai); areaDeps.name = num + areaDeps.name; areaDeps.layers.reserve(area.depLayerCount-1); @@ -138,10 +155,10 @@ void PAKBridge::build() layer.active = layerFlags.flags >> (l-1) & 0x1; /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (layer.name.size() && iswblank(layer.name.back())) + while (layer.name.size() && iswspace(layer.name.back())) layer.name.pop_back(); #else - while (layer.name.size() && isblank(layer.name.back())) + while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif HECL::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); @@ -151,10 +168,13 @@ void PAKBridge::build() for (; r ai) + areaDeps.resources.emplace(mapw[ai]); + ++ai; } } } diff --git a/DataSpec/DNAMP2/MREA.cpp b/DataSpec/DNAMP2/MREA.cpp index ac72bd4c0..724cf388e 100644 --- a/DataSpec/DNAMP2/MREA.cpp +++ b/DataSpec/DNAMP2/MREA.cpp @@ -161,12 +161,17 @@ bool MREA::Extract(const SpecBase& dataSpec, const HECL::ProjectPath& outPath, PAKRouter& pakRouter, const DNAMP1::PAK::Entry& entry, - bool, + bool force, std::function) { using RigPair = std::pair; RigPair dummy(nullptr, nullptr); + /* Rename MREA for consistency */ + HECL::ProjectPath mreaPath(outPath.getParentPath(), _S("!area.blend")); + if (!force && mreaPath.getPathType() == HECL::ProjectPath::PT_FILE) + return true; + /* Do extract */ Header head; head.read(rs); @@ -186,7 +191,7 @@ bool MREA::Extract(const SpecBase& dataSpec, /* Start up blender connection */ HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); - if (!conn.createBlend(outPath, HECL::BlenderConnection::TypeArea)) + if (!conn.createBlend(mreaPath, HECL::BlenderConnection::TypeArea)) return false; /* Open Py Stream and read sections */ diff --git a/DataSpec/DNAMP3/DNAMP3.cpp b/DataSpec/DNAMP3/DNAMP3.cpp index 941369144..91d3cc63b 100644 --- a/DataSpec/DNAMP3/DNAMP3.cpp +++ b/DataSpec/DNAMP3/DNAMP3.cpp @@ -83,9 +83,11 @@ void PAKBridge::build() { Level& level = m_levelDeps[entry.id]; - PAKEntryReadStream rs = entry.beginReadStream(m_node); MLVL mlvl; - mlvl.read(rs); + { + PAKEntryReadStream rs = entry.beginReadStream(m_node); + mlvl.read(rs); + } #if HECL_UCS2 level.name = HECL::UTF8ToWide(m_pak.bestEntryName(entry)); #else @@ -94,6 +96,19 @@ void PAKBridge::build() level.areas.reserve(mlvl.areaCount); unsigned layerIdx = 0; + /* Make MAPW available to lookup MAPAs */ + const PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap); + std::vector mapw; + if (worldMapEnt) + { + PAKEntryReadStream rs = worldMapEnt->beginReadStream(m_node); + rs.seek(8, Athena::Current); + atUint32 areaCount = rs.readUint32Big(); + mapw.reserve(areaCount); + for (atUint32 i=0 ; ibeginReadStream(m_node); - areaName.read(rs); + { + PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node); + areaName.read(rs); + } areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0); /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (areaDeps.name.size() && iswblank(areaDeps.name.back())) + while (areaDeps.name.size() && iswspace(areaDeps.name.back())) areaDeps.name.pop_back(); #else - while (areaDeps.name.size() && isblank(areaDeps.name.back())) + while (areaDeps.name.size() && isspace(areaDeps.name.back())) areaDeps.name.pop_back(); #endif } @@ -134,7 +151,7 @@ void PAKBridge::build() } } HECL::SystemChar num[16]; - HECL::SNPrintf(num, 16, _S("%02u "), ai++); + HECL::SNPrintf(num, 16, _S("%02u "), ai); areaDeps.name = num + areaDeps.name; const MLVL::LayerFlags& areaLayers = *layerFlagsIt++; @@ -149,10 +166,10 @@ void PAKBridge::build() layer.active = areaLayers.flags >> l & 0x1; /* Trim possible trailing whitespace */ #if HECL_UCS2 - while (layer.name.size() && iswblank(layer.name.back())) + while (layer.name.size() && iswspace(layer.name.back())) layer.name.pop_back(); #else - while (layer.name.size() && isblank(layer.name.back())) + while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif HECL::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); @@ -166,8 +183,11 @@ void PAKBridge::build() { PAKEntryReadStream ars = areaEntry->beginReadStream(m_node); MREA::ExtractLayerDeps(ars, areaDeps); - areaDeps.resources.emplace(area.areaMREAId); } + areaDeps.resources.emplace(area.areaMREAId); + if (mapw.size() > ai) + areaDeps.resources.emplace(mapw[ai]); + ++ai; } } } diff --git a/DataSpec/DNAMP3/MREA.cpp b/DataSpec/DNAMP3/MREA.cpp index 363aaad27..fa71e5ffd 100644 --- a/DataSpec/DNAMP3/MREA.cpp +++ b/DataSpec/DNAMP3/MREA.cpp @@ -71,12 +71,17 @@ bool MREA::Extract(const SpecBase& dataSpec, const HECL::ProjectPath& outPath, PAKRouter& pakRouter, const PAK::Entry& entry, - bool, + bool force, std::function) { using RigPair = std::pair; RigPair dummy(nullptr, nullptr); + /* Rename MREA for consistency */ + HECL::ProjectPath mreaPath(outPath.getParentPath(), _S("!area.blend")); + if (!force && mreaPath.getPathType() == HECL::ProjectPath::PT_FILE) + return true; + /* Do extract */ Header head; head.read(rs); @@ -99,7 +104,7 @@ bool MREA::Extract(const SpecBase& dataSpec, /* Start up blender connection */ HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); - if (!conn.createBlend(outPath, HECL::BlenderConnection::TypeArea)) + if (!conn.createBlend(mreaPath, HECL::BlenderConnection::TypeArea)) return false; /* Open Py Stream and read sections */ @@ -267,7 +272,7 @@ bool MREA::ExtractLayerDeps(PAKEntryReadStream& rs, PAKBridge::Level::Area& area for (; r m_nameEntries; std::vector m_entries; + std::vector m_firstEntries; std::unordered_map m_idMap; std::unordered_map m_nameMap; diff --git a/hecl b/hecl index f2870c135..046c0194f 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit f2870c135dc8f7d3b5c582b94474fcc4c5268049 +Subproject commit 046c0194f8b9d22449d4b853397e86783fa14770