mirror of https://github.com/AxioDL/metaforce.git
Added area/layer directory indexing for MP1/2
This commit is contained in:
parent
7b1ec6c4b9
commit
6e58666a80
|
@ -206,13 +206,51 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Resource extractor type */
|
struct UniqueResult
|
||||||
typedef struct
|
|
||||||
{
|
{
|
||||||
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func;
|
enum Type
|
||||||
|
{
|
||||||
|
UNIQUE_NOTFOUND,
|
||||||
|
UNIQUE_LEVEL,
|
||||||
|
UNIQUE_AREA,
|
||||||
|
UNIQUE_LAYER
|
||||||
|
} type = UNIQUE_NOTFOUND;
|
||||||
|
const HECL::SystemString* areaName = nullptr;
|
||||||
|
const HECL::SystemString* layerName = nullptr;
|
||||||
|
UniqueResult() = default;
|
||||||
|
UniqueResult(Type tp) : type(tp) {}
|
||||||
|
inline HECL::ProjectPath uniquePath(const HECL::ProjectPath& pakPath) const
|
||||||
|
{
|
||||||
|
if (type == UNIQUE_AREA)
|
||||||
|
{
|
||||||
|
HECL::ProjectPath areaDir(pakPath, *areaName);
|
||||||
|
areaDir.makeDir();
|
||||||
|
return areaDir;
|
||||||
|
}
|
||||||
|
else if (type == UNIQUE_LAYER)
|
||||||
|
{
|
||||||
|
HECL::ProjectPath areaDir(pakPath, *areaName);
|
||||||
|
areaDir.makeDir();
|
||||||
|
HECL::ProjectPath layerDir(areaDir, *layerName);
|
||||||
|
layerDir.makeDir();
|
||||||
|
return layerDir;
|
||||||
|
}
|
||||||
|
return pakPath;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class BRIDGETYPE>
|
||||||
|
class PAKRouter;
|
||||||
|
|
||||||
|
/* Resource extractor type */
|
||||||
|
template <class PAKBRIDGE>
|
||||||
|
struct ResExtractor
|
||||||
|
{
|
||||||
|
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func_a;
|
||||||
|
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&, PAKRouter<PAKBRIDGE>&)> func_b;
|
||||||
const char* fileExt;
|
const char* fileExt;
|
||||||
unsigned weight;
|
unsigned weight;
|
||||||
} ResExtractor;
|
};
|
||||||
|
|
||||||
/* PAKRouter (for detecting shared entry locations) */
|
/* PAKRouter (for detecting shared entry locations) */
|
||||||
template <class BRIDGETYPE>
|
template <class BRIDGETYPE>
|
||||||
|
@ -232,14 +270,17 @@ public:
|
||||||
PAKRouter(const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
|
PAKRouter(const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
|
||||||
: m_gameWorking(working), m_gameCooked(cooked),
|
: m_gameWorking(working), m_gameCooked(cooked),
|
||||||
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
|
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
|
||||||
void build(const std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
|
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
m_uniqueEntries.clear();
|
m_uniqueEntries.clear();
|
||||||
m_sharedEntries.clear();
|
m_sharedEntries.clear();
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
float bridgesSz = bridges.size();
|
float bridgesSz = bridges.size();
|
||||||
for (const BRIDGETYPE& bridge : bridges)
|
|
||||||
|
/* Route entries unique/shared per-pak */
|
||||||
|
for (BRIDGETYPE& bridge : bridges)
|
||||||
{
|
{
|
||||||
|
bridge.build();
|
||||||
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
|
const typename BRIDGETYPE::PAKType& pak = bridge.getPAK();
|
||||||
for (const auto& entry : pak.m_idMap)
|
for (const auto& entry : pak.m_idMap)
|
||||||
{
|
{
|
||||||
|
@ -274,7 +315,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
HECL::ProjectPath getWorking(const typename BRIDGETYPE::PAKType::Entry* entry,
|
HECL::ProjectPath getWorking(const typename BRIDGETYPE::PAKType::Entry* entry,
|
||||||
const ResExtractor& extractor) const
|
const ResExtractor<BRIDGETYPE>& extractor) const
|
||||||
{
|
{
|
||||||
if (!m_pak)
|
if (!m_pak)
|
||||||
LogDNACommon.report(LogVisor::FatalError,
|
LogDNACommon.report(LogVisor::FatalError,
|
||||||
|
@ -282,10 +323,11 @@ public:
|
||||||
auto uniqueSearch = m_uniqueEntries.find(entry->id);
|
auto uniqueSearch = m_uniqueEntries.find(entry->id);
|
||||||
if (uniqueSearch != m_uniqueEntries.end())
|
if (uniqueSearch != m_uniqueEntries.end())
|
||||||
{
|
{
|
||||||
|
HECL::ProjectPath uniquePath = entry->unique.uniquePath(m_pakWorking);
|
||||||
HECL::SystemString entName = m_pak->bestEntryName(*entry);
|
HECL::SystemString entName = m_pak->bestEntryName(*entry);
|
||||||
if (extractor.fileExt)
|
if (extractor.fileExt)
|
||||||
entName += extractor.fileExt;
|
entName += extractor.fileExt;
|
||||||
return HECL::ProjectPath(m_pakWorking, entName);
|
return HECL::ProjectPath(uniquePath, entName);
|
||||||
}
|
}
|
||||||
auto sharedSearch = m_sharedEntries.find(entry->id);
|
auto sharedSearch = m_sharedEntries.find(entry->id);
|
||||||
if (sharedSearch != m_sharedEntries.end())
|
if (sharedSearch != m_sharedEntries.end())
|
||||||
|
@ -295,7 +337,7 @@ public:
|
||||||
entName += extractor.fileExt;
|
entName += extractor.fileExt;
|
||||||
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
|
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
|
||||||
HECL::ProjectPath uniquePath(m_pakWorking, entName);
|
HECL::ProjectPath uniquePath(m_pakWorking, entName);
|
||||||
if (extractor.func)
|
if (extractor.func_a || extractor.func_b)
|
||||||
uniquePath.makeLinkTo(sharedPath);
|
uniquePath.makeLinkTo(sharedPath);
|
||||||
m_sharedWorking.makeDir();
|
m_sharedWorking.makeDir();
|
||||||
return sharedPath;
|
return sharedPath;
|
||||||
|
@ -312,7 +354,8 @@ public:
|
||||||
auto uniqueSearch = m_uniqueEntries.find(entry->id);
|
auto uniqueSearch = m_uniqueEntries.find(entry->id);
|
||||||
if (uniqueSearch != m_uniqueEntries.end())
|
if (uniqueSearch != m_uniqueEntries.end())
|
||||||
{
|
{
|
||||||
return HECL::ProjectPath(m_pakCooked, m_pak->bestEntryName(*entry));
|
HECL::ProjectPath uniquePath = entry->unique.uniquePath(m_pakCooked);
|
||||||
|
return HECL::ProjectPath(uniquePath, m_pak->bestEntryName(*entry));
|
||||||
}
|
}
|
||||||
auto sharedSearch = m_sharedEntries.find(entry->id);
|
auto sharedSearch = m_sharedEntries.find(entry->id);
|
||||||
if (sharedSearch != m_sharedEntries.end())
|
if (sharedSearch != m_sharedEntries.end())
|
||||||
|
@ -334,7 +377,7 @@ public:
|
||||||
{
|
{
|
||||||
for (const auto& item : m_pak->m_idMap)
|
for (const auto& item : m_pak->m_idMap)
|
||||||
{
|
{
|
||||||
ResExtractor extractor = BRIDGETYPE::LookupExtractor(*item.second);
|
ResExtractor<BRIDGETYPE> extractor = BRIDGETYPE::LookupExtractor(*item.second);
|
||||||
if (extractor.weight != w)
|
if (extractor.weight != w)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -348,12 +391,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
HECL::ProjectPath working = getWorking(item.second, extractor);
|
HECL::ProjectPath working = getWorking(item.second, extractor);
|
||||||
if (extractor.func)
|
if (extractor.func_a) /* Doesn't need PAKRouter access */
|
||||||
{
|
{
|
||||||
if (force || working.getPathType() == HECL::ProjectPath::PT_NONE)
|
if (force || working.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
{
|
{
|
||||||
PAKEntryReadStream s = item.second->beginReadStream(*m_node);
|
PAKEntryReadStream s = item.second->beginReadStream(*m_node);
|
||||||
extractor.func(s, working);
|
extractor.func_a(s, working);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (extractor.func_b) /* Needs PAKRouter access */
|
||||||
|
{
|
||||||
|
if (force || working.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||||
|
{
|
||||||
|
PAKEntryReadStream s = item.second->beginReadStream(*m_node);
|
||||||
|
extractor.func_b(s, working, *this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,11 @@ namespace Retro
|
||||||
namespace DNAMP1
|
namespace DNAMP1
|
||||||
{
|
{
|
||||||
|
|
||||||
bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReader& reader)
|
bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
|
Athena::io::IStreamReader& reader,
|
||||||
|
PAKRouter<PAKBridge>& pakRouter)
|
||||||
{
|
{
|
||||||
|
return true;
|
||||||
reader.setEndian(Athena::BigEndian);
|
reader.setEndian(Athena::BigEndian);
|
||||||
|
|
||||||
CMDL::Header head;
|
CMDL::Header head;
|
||||||
|
@ -30,7 +33,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
/* Open Py Stream */
|
/* Open Py Stream */
|
||||||
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
||||||
os << "import bmesh\n"
|
os << "import bmesh\n"
|
||||||
"import bpy;\n";
|
"import bpy\n"
|
||||||
"bm = bmesh.new()\n";
|
"bm = bmesh.new()\n";
|
||||||
MaterialSet::RegisterMaterialProps(os);
|
MaterialSet::RegisterMaterialProps(os);
|
||||||
|
|
||||||
|
@ -38,6 +41,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
atUint64 secStart = reader.position();
|
atUint64 secStart = reader.position();
|
||||||
|
|
||||||
|
/*
|
||||||
std::unique_ptr<atVec3f[]> vertPos;
|
std::unique_ptr<atVec3f[]> vertPos;
|
||||||
std::unique_ptr<atVec3f[]> vertNorm;
|
std::unique_ptr<atVec3f[]> vertNorm;
|
||||||
typedef atInt16 ShortVec3[3];
|
typedef atInt16 ShortVec3[3];
|
||||||
|
@ -45,11 +49,44 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
std::unique_ptr<atVec2f[]> vertUVs;
|
std::unique_ptr<atVec2f[]> vertUVs;
|
||||||
typedef atInt16 ShortVec2[2];
|
typedef atInt16 ShortVec2[2];
|
||||||
std::unique_ptr<ShortVec2[]> vertUVsShort;
|
std::unique_ptr<ShortVec2[]> vertUVsShort;
|
||||||
|
*/
|
||||||
|
std::vector<std::vector<unsigned>> matUVCounts;
|
||||||
|
matUVCounts.reserve(head.matSetCount);
|
||||||
bool visitedDLOffsets = false;
|
bool visitedDLOffsets = false;
|
||||||
if (s < head.matSetCount)
|
if (s < head.matSetCount)
|
||||||
{
|
{
|
||||||
MaterialSet matSet;
|
MaterialSet matSet;
|
||||||
matSet.read(reader);
|
matSet.read(reader);
|
||||||
|
|
||||||
|
/* Texmaps */
|
||||||
|
os << "texmap_list = []\n";
|
||||||
|
for (const UniqueID32& tex : matSet.head.textureIDs)
|
||||||
|
{
|
||||||
|
os.format("if '%s' in bpy.data.textures:\n"
|
||||||
|
" image = bpy.data.images['%s']\n"
|
||||||
|
" texture = bpy.data.textures[image.name]\n"
|
||||||
|
"else:\n"
|
||||||
|
" image_path = os.path.relpath('../../%s/textures/%s.png')\n"
|
||||||
|
" print(os.getcwd()+image_path)\n"
|
||||||
|
" image = bpy.data.images.load('//' + image_path)\n"
|
||||||
|
" image.name = '%s'\n"
|
||||||
|
" texture = bpy.data.textures.new(image.name, 'IMAGE')\n"
|
||||||
|
" texture.image = image\n"
|
||||||
|
"texmap_list.append(texture)\n"
|
||||||
|
"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
matUVCounts.emplace_back();
|
||||||
|
std::vector<unsigned>& uvCounts = matUVCounts.back();
|
||||||
|
uvCounts.reserve(matSet.head.materialCount);
|
||||||
|
|
||||||
|
unsigned m=0;
|
||||||
|
for (const MaterialSet::Material& mat : matSet.materials)
|
||||||
|
{
|
||||||
|
uvCounts.emplace_back();
|
||||||
|
unsigned& uvCount = uvCounts.back();
|
||||||
|
MaterialSet::ConstructMaterial(os, mat, s, m++, uvCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -59,31 +96,44 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
/* Positions */
|
/* Positions */
|
||||||
size_t vertCount = head.secSizes[s] / 12;
|
size_t vertCount = head.secSizes[s] / 12;
|
||||||
vertPos.reset(new atVec3f[vertCount]);
|
//vertPos.reset(new atVec3f[vertCount]);
|
||||||
for (size_t i=0 ; i<vertCount ; ++i)
|
for (size_t i=0 ; i<vertCount ; ++i)
|
||||||
vertPos[i] = reader.readVec3f();
|
{
|
||||||
|
//vertPos[i] = reader.readVec3f();
|
||||||
|
atVec3f pos = reader.readVec3f();
|
||||||
|
os.format("bm.verts.new(co=(%f,%f,%f))\n",
|
||||||
|
pos.vec[0], pos.vec[1], pos.vec[2]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
/* Normals */
|
/* Normals */
|
||||||
|
os << "normals = []\n";
|
||||||
if (head.flags.shortNormals())
|
if (head.flags.shortNormals())
|
||||||
{
|
{
|
||||||
size_t normCount = head.secSizes[s] / 6;
|
size_t normCount = head.secSizes[s] / 6;
|
||||||
vertNormShort.reset(new ShortVec3[normCount]);
|
//vertNormShort.reset(new ShortVec3[normCount]);
|
||||||
for (size_t i=0 ; i<normCount ; ++i)
|
for (size_t i=0 ; i<normCount ; ++i)
|
||||||
{
|
{
|
||||||
vertNormShort[i][0] = reader.readInt16();
|
//vertNormShort[i][0] = reader.readInt16();
|
||||||
vertNormShort[i][1] = reader.readInt16();
|
//vertNormShort[i][1] = reader.readInt16();
|
||||||
vertNormShort[i][2] = reader.readInt16();
|
//vertNormShort[i][2] = reader.readInt16();
|
||||||
|
os.format("normals.append((%f,%f,%f))\n",
|
||||||
|
reader.readInt16(), reader.readInt16(), reader.readInt16());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t normCount = head.secSizes[s] / 12;
|
size_t normCount = head.secSizes[s] / 12;
|
||||||
vertNorm.reset(new atVec3f[normCount]);
|
//vertNorm.reset(new atVec3f[normCount]);
|
||||||
for (size_t i=0 ; i<normCount ; ++i)
|
for (size_t i=0 ; i<normCount ; ++i)
|
||||||
vertNorm[i] = reader.readVec3f();
|
{
|
||||||
|
//vertNorm[i] = reader.readVec3f();
|
||||||
|
atVec3f norm = reader.readVec3f();
|
||||||
|
os.format("normals.append((%f,%f,%f))\n",
|
||||||
|
norm.vec[0], norm.vec[1], norm.vec[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -95,23 +145,30 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
/* Float UVs */
|
/* Float UVs */
|
||||||
|
os << "uv_list = []\n";
|
||||||
size_t uvCount = head.secSizes[s] / 8;
|
size_t uvCount = head.secSizes[s] / 8;
|
||||||
vertUVs.reset(new atVec2f[uvCount]);
|
//vertUVs.reset(new atVec2f[uvCount]);
|
||||||
for (size_t i=0 ; i<uvCount ; ++i)
|
for (size_t i=0 ; i<uvCount ; ++i)
|
||||||
vertUVs[i] = reader.readVec2f();
|
{
|
||||||
|
//vertUVs[i] = reader.readVec2f();
|
||||||
|
atVec2f uv = reader.readVec2f();
|
||||||
|
os.format("uv_list.append((%f,%f))\n",
|
||||||
|
uv.vec[0], uv.vec[1]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
/* Short UVs */
|
/* Short UVs */
|
||||||
|
os << "suv_list = []\n";
|
||||||
if (head.flags.shortUVs())
|
if (head.flags.shortUVs())
|
||||||
{
|
{
|
||||||
size_t uvCount = head.secSizes[s] / 4;
|
size_t uvCount = head.secSizes[s] / 4;
|
||||||
vertUVsShort.reset(new ShortVec2[uvCount]);
|
//vertUVsShort.reset(new ShortVec2[uvCount]);
|
||||||
for (size_t i=0 ; i<uvCount ; ++i)
|
for (size_t i=0 ; i<uvCount ; ++i)
|
||||||
{
|
{
|
||||||
vertUVsShort[i][0] = reader.readInt16();
|
os.format("suv_list.append((%f,%f))\n",
|
||||||
vertUVsShort[i][1] = reader.readInt16();
|
reader.readInt16(), reader.readInt16());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +188,6 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
|
||||||
/* GX Display List (surface) */
|
/* GX Display List (surface) */
|
||||||
SurfaceHeader sHead;
|
SurfaceHeader sHead;
|
||||||
sHead.read(reader);
|
sHead.read(reader);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../DNACommon/DNACommon.hpp"
|
#include "../DNACommon/DNACommon.hpp"
|
||||||
#include "CMDLMaterials.hpp"
|
#include "CMDLMaterials.hpp"
|
||||||
#include "BlenderConnection.hpp"
|
#include "BlenderConnection.hpp"
|
||||||
|
#include "DNAMP1.hpp"
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
|
@ -48,14 +49,18 @@ struct CMDL
|
||||||
Align<32> align;
|
Align<32> align;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReader& reader);
|
static bool ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
|
Athena::io::IStreamReader& reader,
|
||||||
|
PAKRouter<PAKBridge>& pakRouter);
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
static bool Extract(PAKEntryReadStream& rs,
|
||||||
|
const HECL::ProjectPath& outPath,
|
||||||
|
PAKRouter<PAKBridge>& pakRouter)
|
||||||
{
|
{
|
||||||
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
|
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
|
||||||
if (!conn.createBlend(outPath.getAbsolutePath()))
|
if (!conn.createBlend(outPath.getAbsolutePath()))
|
||||||
return false;
|
return false;
|
||||||
return ReadToBlender(conn, rs);
|
return ReadToBlender(conn, rs, pakRouter);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
|
||||||
{
|
{
|
||||||
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
||||||
m_pak.read(rs);
|
m_pak.read(rs);
|
||||||
}
|
|
||||||
|
|
||||||
HECL::SystemString PAKBridge::getLevelString() const
|
/* Append Level String */
|
||||||
{
|
|
||||||
HECL::SystemString retval;
|
|
||||||
for (const PAK::Entry& entry : m_pak.m_entries)
|
for (const PAK::Entry& entry : m_pak.m_entries)
|
||||||
{
|
{
|
||||||
if (entry.type == Retro::MLVL)
|
if (entry.type == Retro::MLVL)
|
||||||
|
@ -36,27 +33,147 @@ HECL::SystemString PAKBridge::getLevelString() const
|
||||||
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
|
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
|
||||||
STRG mlvlName;
|
STRG mlvlName;
|
||||||
mlvlName.read(rs);
|
mlvlName.read(rs);
|
||||||
if (retval.size())
|
if (m_levelString.size())
|
||||||
retval += _S(", ");
|
m_levelString += _S(", ");
|
||||||
retval += mlvlName.getSystemString(ENGL, 0);
|
m_levelString += mlvlName.getSystemString(ENGL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqueResult PAKBridge::uniqueCheck(const PAK::Entry& entry)
|
||||||
|
{
|
||||||
|
UniqueResult::Type result = UniqueResult::UNIQUE_NOTFOUND;
|
||||||
|
bool foundOneLayer = false;
|
||||||
|
UniqueID32 areaId;
|
||||||
|
unsigned layerIdx;
|
||||||
|
for (const auto& pair : m_areaDeps)
|
||||||
|
{
|
||||||
|
unsigned l=0;
|
||||||
|
for (const auto& layer : pair.second.layers)
|
||||||
|
{
|
||||||
|
if (layer.resources.find(entry.id) != layer.resources.end())
|
||||||
|
{
|
||||||
|
if (foundOneLayer)
|
||||||
|
{
|
||||||
|
if (areaId == pair.first)
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
else
|
||||||
|
return {UniqueResult::UNIQUE_LEVEL};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = UniqueResult::UNIQUE_LAYER;
|
||||||
|
areaId = pair.first;
|
||||||
|
layerIdx = l;
|
||||||
|
foundOneLayer = true;
|
||||||
|
}
|
||||||
|
++l;
|
||||||
|
}
|
||||||
|
if (pair.second.resources.find(entry.id) != pair.second.resources.end())
|
||||||
|
{
|
||||||
|
if (foundOneLayer)
|
||||||
|
{
|
||||||
|
if (areaId == pair.first)
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
else
|
||||||
|
return {UniqueResult::UNIQUE_LEVEL};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
areaId = pair.first;
|
||||||
|
foundOneLayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UniqueResult retval = {result};
|
||||||
|
if (result == UniqueResult::UNIQUE_LAYER || result == UniqueResult::UNIQUE_AREA)
|
||||||
|
{
|
||||||
|
const PAKBridge::Area& area = m_areaDeps[areaId];
|
||||||
|
retval.areaName = &area.name;
|
||||||
|
if (result == UniqueResult::UNIQUE_LAYER)
|
||||||
|
{
|
||||||
|
const PAKBridge::Area::Layer& layer = area.layers[layerIdx];
|
||||||
|
retval.layerName = &layer.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
static HECL::SystemString LayerName(const std::string& name)
|
||||||
|
{
|
||||||
|
#if HECL_UCS2
|
||||||
|
HECL::SystemString ret = HECL::UTF8ToWide(mlvl.layerNames[layerIdx++]);
|
||||||
|
#else
|
||||||
|
HECL::SystemString ret = name;
|
||||||
|
#endif
|
||||||
|
for (auto& ch : ret)
|
||||||
|
if (ch == _S('/') || ch == _S('\\'))
|
||||||
|
ch = _S('-');
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PAKBridge::build()
|
||||||
|
{
|
||||||
|
/* First pass: build per-area/per-layer dependency map */
|
||||||
|
for (const PAK::Entry& entry : m_pak.m_entries)
|
||||||
|
{
|
||||||
|
if (entry.type == Retro::MLVL)
|
||||||
|
{
|
||||||
|
PAKEntryReadStream rs = entry.beginReadStream(m_node);
|
||||||
|
MLVL mlvl;
|
||||||
|
mlvl.read(rs);
|
||||||
|
m_areaDeps.reserve(mlvl.areaCount);
|
||||||
|
unsigned layerIdx = 0;
|
||||||
|
for (const MLVL::Area& area : mlvl.areas)
|
||||||
|
{
|
||||||
|
Area& areaDeps = m_areaDeps[area.areaMREAId];
|
||||||
|
const PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
|
||||||
|
if (areaNameEnt)
|
||||||
|
{
|
||||||
|
STRG areaName;
|
||||||
|
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
|
||||||
|
areaName.read(rs);
|
||||||
|
areaDeps.name = areaName.getSystemString(Retro::ENGL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
areaDeps.layers.reserve(area.depLayerCount-1);
|
||||||
|
unsigned r=0;
|
||||||
|
for (unsigned l=1 ; l<area.depLayerCount ; ++l)
|
||||||
|
{
|
||||||
|
areaDeps.layers.emplace_back();
|
||||||
|
Area::Layer& layer = areaDeps.layers.back();
|
||||||
|
layer.name = LayerName(mlvl.layerNames[layerIdx++]);
|
||||||
|
layer.resources.reserve(area.depLayers[l] - r);
|
||||||
|
for (; r<area.depLayers[l] ; ++r)
|
||||||
|
layer.resources.emplace(area.deps[r].id);
|
||||||
|
}
|
||||||
|
areaDeps.resources.reserve(area.depCount - r);
|
||||||
|
for (; r<area.depCount ; ++r)
|
||||||
|
areaDeps.resources.emplace(area.deps[r].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second pass: cross-compare uniqueness */
|
||||||
|
for (PAK::Entry& entry : m_pak.m_entries)
|
||||||
|
{
|
||||||
|
entry.unique = uniqueCheck(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
||||||
{
|
{
|
||||||
switch (entry.type.toUint32())
|
switch (entry.type.toUint32())
|
||||||
{
|
{
|
||||||
case SBIG('STRG'):
|
case SBIG('STRG'):
|
||||||
return {STRG::Extract, ".yaml"};
|
return {STRG::Extract, nullptr, ".yaml"};
|
||||||
case SBIG('TXTR'):
|
case SBIG('TXTR'):
|
||||||
return {TXTR::Extract, ".png"};
|
return {TXTR::Extract, nullptr, ".png"};
|
||||||
case SBIG('CMDL'):
|
case SBIG('CMDL'):
|
||||||
return {CMDL::Extract, ".blend", 1};
|
return {nullptr, CMDL::Extract, ".blend", 1};
|
||||||
case SBIG('MLVL'):
|
case SBIG('MLVL'):
|
||||||
return {MLVL::Extract, ".yaml"};
|
return {MLVL::Extract, nullptr, ".yaml"};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,26 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
PAK m_pak;
|
PAK m_pak;
|
||||||
|
struct Area
|
||||||
|
{
|
||||||
|
HECL::SystemString name;
|
||||||
|
struct Layer
|
||||||
|
{
|
||||||
|
HECL::SystemString name;
|
||||||
|
std::unordered_set<UniqueID32> resources;
|
||||||
|
};
|
||||||
|
std::vector<Layer> layers;
|
||||||
|
std::unordered_set<UniqueID32> resources;
|
||||||
|
};
|
||||||
|
std::unordered_map<UniqueID32, Area> m_areaDeps;
|
||||||
|
HECL::SystemString m_levelString;
|
||||||
|
UniqueResult uniqueCheck(const PAK::Entry& entry);
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
void build();
|
||||||
const std::string& getName() const {return m_node.getName();}
|
static ResExtractor<PAKBridge> LookupExtractor(const PAK::Entry& entry);
|
||||||
HECL::SystemString getLevelString() const;
|
inline const std::string& getName() const {return m_node.getName();}
|
||||||
|
inline const HECL::SystemString& getLevelString() const {return m_levelString;}
|
||||||
|
|
||||||
typedef PAK PAKType;
|
typedef PAK PAKType;
|
||||||
inline const PAKType& getPAK() const {return m_pak;}
|
inline const PAKType& getPAK() const {return m_pak;}
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct PAK : BigDNA
|
||||||
UniqueID32 id;
|
UniqueID32 id;
|
||||||
Value<atUint32> size;
|
Value<atUint32> size;
|
||||||
Value<atUint32> offset;
|
Value<atUint32> offset;
|
||||||
|
UniqueResult unique;
|
||||||
|
|
||||||
std::unique_ptr<atUint8[]> getBuffer(const NOD::DiscBase::IPartition::Node& pak, atUint64& szOut) const;
|
std::unique_ptr<atUint8[]> getBuffer(const NOD::DiscBase::IPartition::Node& pak, atUint64& szOut) const;
|
||||||
inline PAKEntryReadStream beginReadStream(const NOD::DiscBase::IPartition::Node& pak, atUint64 off=0) const
|
inline PAKEntryReadStream beginReadStream(const NOD::DiscBase::IPartition::Node& pak, atUint64 off=0) const
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "../DNACommon/DNACommon.hpp"
|
#include "../DNACommon/DNACommon.hpp"
|
||||||
#include "../DNACommon/STRG.hpp"
|
#include "../DNACommon/STRG.hpp"
|
||||||
|
#include "DNAMP1.hpp"
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,11 +16,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
|
||||||
{
|
{
|
||||||
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
||||||
m_pak.read(rs);
|
m_pak.read(rs);
|
||||||
}
|
|
||||||
|
|
||||||
HECL::SystemString PAKBridge::getLevelString() const
|
/* Append Level String */
|
||||||
{
|
|
||||||
HECL::SystemString retval;
|
|
||||||
for (const DNAMP1::PAK::Entry& entry : m_pak.m_entries)
|
for (const DNAMP1::PAK::Entry& entry : m_pak.m_entries)
|
||||||
{
|
{
|
||||||
if (entry.type == Retro::MLVL)
|
if (entry.type == Retro::MLVL)
|
||||||
|
@ -34,23 +31,143 @@ HECL::SystemString PAKBridge::getLevelString() const
|
||||||
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
|
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
|
||||||
STRG mlvlName;
|
STRG mlvlName;
|
||||||
mlvlName.read(rs);
|
mlvlName.read(rs);
|
||||||
if (retval.size())
|
if (m_levelString.size())
|
||||||
retval += _S(", ");
|
m_levelString += _S(", ");
|
||||||
retval += mlvlName.getSystemString(ENGL, 0);
|
m_levelString += mlvlName.getSystemString(ENGL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqueResult PAKBridge::uniqueCheck(const DNAMP1::PAK::Entry& entry)
|
||||||
|
{
|
||||||
|
UniqueResult::Type result = UniqueResult::UNIQUE_NOTFOUND;
|
||||||
|
bool foundOneLayer = false;
|
||||||
|
UniqueID32 areaId;
|
||||||
|
unsigned layerIdx;
|
||||||
|
for (const auto& pair : m_areaDeps)
|
||||||
|
{
|
||||||
|
unsigned l=0;
|
||||||
|
for (const auto& layer : pair.second.layers)
|
||||||
|
{
|
||||||
|
if (layer.resources.find(entry.id) != layer.resources.end())
|
||||||
|
{
|
||||||
|
if (foundOneLayer)
|
||||||
|
{
|
||||||
|
if (areaId == pair.first)
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
else
|
||||||
|
return {UniqueResult::UNIQUE_LEVEL};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = UniqueResult::UNIQUE_LAYER;
|
||||||
|
areaId = pair.first;
|
||||||
|
layerIdx = l;
|
||||||
|
foundOneLayer = true;
|
||||||
|
}
|
||||||
|
++l;
|
||||||
|
}
|
||||||
|
if (pair.second.resources.find(entry.id) != pair.second.resources.end())
|
||||||
|
{
|
||||||
|
if (foundOneLayer)
|
||||||
|
{
|
||||||
|
if (areaId == pair.first)
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
else
|
||||||
|
return {UniqueResult::UNIQUE_LEVEL};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = UniqueResult::UNIQUE_AREA;
|
||||||
|
areaId = pair.first;
|
||||||
|
foundOneLayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UniqueResult retval = {result};
|
||||||
|
if (result == UniqueResult::UNIQUE_LAYER || result == UniqueResult::UNIQUE_AREA)
|
||||||
|
{
|
||||||
|
const PAKBridge::Area& area = m_areaDeps[areaId];
|
||||||
|
retval.areaName = &area.name;
|
||||||
|
if (result == UniqueResult::UNIQUE_LAYER)
|
||||||
|
{
|
||||||
|
const PAKBridge::Area::Layer& layer = area.layers[layerIdx];
|
||||||
|
retval.layerName = &layer.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResExtractor PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry)
|
static HECL::SystemString LayerName(const std::string& name)
|
||||||
|
{
|
||||||
|
#if HECL_UCS2
|
||||||
|
HECL::SystemString ret = HECL::UTF8ToWide(mlvl.layerNames[layerIdx++]);
|
||||||
|
#else
|
||||||
|
HECL::SystemString ret = name;
|
||||||
|
#endif
|
||||||
|
for (auto& ch : ret)
|
||||||
|
if (ch == _S('/') || ch == _S('\\'))
|
||||||
|
ch = _S('-');
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PAKBridge::build()
|
||||||
|
{
|
||||||
|
/* First pass: build per-area/per-layer dependency map */
|
||||||
|
for (const DNAMP1::PAK::Entry& entry : m_pak.m_entries)
|
||||||
|
{
|
||||||
|
if (entry.type == Retro::MLVL)
|
||||||
|
{
|
||||||
|
PAKEntryReadStream rs = entry.beginReadStream(m_node);
|
||||||
|
MLVL mlvl;
|
||||||
|
mlvl.read(rs);
|
||||||
|
m_areaDeps.reserve(mlvl.areaCount);
|
||||||
|
unsigned layerIdx = 0;
|
||||||
|
for (const MLVL::Area& area : mlvl.areas)
|
||||||
|
{
|
||||||
|
Area& areaDeps = m_areaDeps[area.areaMREAId];
|
||||||
|
const DNAMP1::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
|
||||||
|
if (areaNameEnt)
|
||||||
|
{
|
||||||
|
STRG areaName;
|
||||||
|
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
|
||||||
|
areaName.read(rs);
|
||||||
|
areaDeps.name = areaName.getSystemString(Retro::ENGL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
areaDeps.layers.reserve(area.depLayerCount-1);
|
||||||
|
unsigned r=0;
|
||||||
|
for (unsigned l=1 ; l<area.depLayerCount ; ++l)
|
||||||
|
{
|
||||||
|
areaDeps.layers.emplace_back();
|
||||||
|
Area::Layer& layer = areaDeps.layers.back();
|
||||||
|
layer.name = LayerName(mlvl.layerNames[layerIdx++]);
|
||||||
|
layer.resources.reserve(area.depLayers[l] - r);
|
||||||
|
for (; r<area.depLayers[l] ; ++r)
|
||||||
|
layer.resources.emplace(area.deps[r].id);
|
||||||
|
}
|
||||||
|
areaDeps.resources.reserve(area.depCount - r);
|
||||||
|
for (; r<area.depCount ; ++r)
|
||||||
|
areaDeps.resources.emplace(area.deps[r].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second pass: cross-compare uniqueness */
|
||||||
|
for (DNAMP1::PAK::Entry& entry : m_pak.m_entries)
|
||||||
|
{
|
||||||
|
entry.unique = uniqueCheck(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry)
|
||||||
{
|
{
|
||||||
switch (entry.type.toUint32())
|
switch (entry.type.toUint32())
|
||||||
{
|
{
|
||||||
case SBIG('STRG'):
|
case SBIG('STRG'):
|
||||||
return {STRG::Extract, ".as"};
|
return {STRG::Extract, nullptr, ".as"};
|
||||||
case SBIG('TXTR'):
|
case SBIG('TXTR'):
|
||||||
return {TXTR::Extract, ".png"};
|
return {TXTR::Extract, nullptr, ".png"};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,26 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
DNAMP1::PAK m_pak;
|
DNAMP1::PAK m_pak;
|
||||||
|
struct Area
|
||||||
|
{
|
||||||
|
HECL::SystemString name;
|
||||||
|
struct Layer
|
||||||
|
{
|
||||||
|
HECL::SystemString name;
|
||||||
|
std::unordered_set<UniqueID32> resources;
|
||||||
|
};
|
||||||
|
std::vector<Layer> layers;
|
||||||
|
std::unordered_set<UniqueID32> resources;
|
||||||
|
};
|
||||||
|
std::unordered_map<UniqueID32, Area> m_areaDeps;
|
||||||
|
HECL::SystemString m_levelString;
|
||||||
|
UniqueResult uniqueCheck(const DNAMP1::PAK::Entry& entry);
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry);
|
void build();
|
||||||
const std::string& getName() const {return m_node.getName();}
|
static ResExtractor<PAKBridge> LookupExtractor(const DNAMP1::PAK::Entry& entry);
|
||||||
HECL::SystemString getLevelString() const;
|
inline const std::string& getName() const {return m_node.getName();}
|
||||||
|
inline const HECL::SystemString& getLevelString() const {return m_levelString;}
|
||||||
|
|
||||||
typedef DNAMP1::PAK PAKType;
|
typedef DNAMP1::PAK PAKType;
|
||||||
inline const PAKType& getPAK() const {return m_pak;}
|
inline const PAKType& getPAK() const {return m_pak;}
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct MLVL : BigDNA
|
||||||
|
|
||||||
String<-1> internalAreaName;
|
String<-1> internalAreaName;
|
||||||
};
|
};
|
||||||
|
Vector<Area, DNA_COUNT(areaCount)> areas;
|
||||||
|
|
||||||
UniqueID32 worldMap;
|
UniqueID32 worldMap;
|
||||||
Value<atUint8> unknown2;
|
Value<atUint8> unknown2;
|
||||||
|
|
|
@ -18,10 +18,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
|
||||||
{
|
{
|
||||||
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
NOD::AthenaPartReadStream rs(node.beginReadStream());
|
||||||
m_pak.read(rs);
|
m_pak.read(rs);
|
||||||
}
|
|
||||||
|
|
||||||
HECL::SystemString PAKBridge::getLevelString() const
|
/* Append Level String */
|
||||||
{
|
|
||||||
std::set<HECL::SystemString, CaseInsensitiveCompare> uniq;
|
std::set<HECL::SystemString, CaseInsensitiveCompare> uniq;
|
||||||
for (const PAK::Entry& entry : m_pak.m_entries)
|
for (const PAK::Entry& entry : m_pak.m_entries)
|
||||||
{
|
{
|
||||||
|
@ -40,26 +38,28 @@ HECL::SystemString PAKBridge::getLevelString() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HECL::SystemString retval;
|
|
||||||
bool comma = false;
|
bool comma = false;
|
||||||
for (const HECL::SystemString& str : uniq)
|
for (const HECL::SystemString& str : uniq)
|
||||||
{
|
{
|
||||||
if (comma)
|
if (comma)
|
||||||
retval += _S(", ");
|
m_levelString += _S(", ");
|
||||||
comma = true;
|
comma = true;
|
||||||
retval += str;
|
m_levelString += str;
|
||||||
}
|
}
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
void PAKBridge::build()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const PAK::Entry& entry)
|
||||||
{
|
{
|
||||||
switch (entry.type.toUint32())
|
switch (entry.type.toUint32())
|
||||||
{
|
{
|
||||||
case SBIG('STRG'):
|
case SBIG('STRG'):
|
||||||
return {STRG::Extract, ".as"};
|
return {STRG::Extract, nullptr, ".as"};
|
||||||
case SBIG('TXTR'):
|
case SBIG('TXTR'):
|
||||||
return {TXTR::Extract, ".png"};
|
return {TXTR::Extract, nullptr, ".png"};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,13 @@ class PAKBridge
|
||||||
HECL::Database::Project& m_project;
|
HECL::Database::Project& m_project;
|
||||||
const NOD::DiscBase::IPartition::Node& m_node;
|
const NOD::DiscBase::IPartition::Node& m_node;
|
||||||
PAK m_pak;
|
PAK m_pak;
|
||||||
|
HECL::SystemString m_levelString;
|
||||||
public:
|
public:
|
||||||
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
|
||||||
static ResExtractor LookupExtractor(const PAK::Entry& entry);
|
void build();
|
||||||
const std::string& getName() const {return m_node.getName();}
|
static ResExtractor<PAKBridge> LookupExtractor(const PAK::Entry& entry);
|
||||||
HECL::SystemString getLevelString() const;
|
inline const std::string& getName() const {return m_node.getName();}
|
||||||
|
inline HECL::SystemString getLevelString() const {return m_levelString;}
|
||||||
|
|
||||||
typedef PAK PAKType;
|
typedef PAK PAKType;
|
||||||
inline const PAKType& getPAK() const {return m_pak;}
|
inline const PAKType& getPAK() const {return m_pak;}
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct PAK : BigDNA
|
||||||
UniqueID64 id;
|
UniqueID64 id;
|
||||||
Value<atUint32> size;
|
Value<atUint32> size;
|
||||||
Value<atUint32> offset;
|
Value<atUint32> offset;
|
||||||
|
UniqueResult unique;
|
||||||
|
|
||||||
std::unique_ptr<atUint8[]> getBuffer(const NOD::DiscBase::IPartition::Node& pak, atUint64& szOut) const;
|
std::unique_ptr<atUint8[]> getBuffer(const NOD::DiscBase::IPartition::Node& pak, atUint64& szOut) const;
|
||||||
inline PAKEntryReadStream beginReadStream(const NOD::DiscBase::IPartition::Node& pak, atUint64 off=0) const
|
inline PAKEntryReadStream beginReadStream(const NOD::DiscBase::IPartition::Node& pak, atUint64 off=0) const
|
||||||
|
|
Loading…
Reference in New Issue