Added area/layer directory indexing for MP1/2

This commit is contained in:
Jack Andersen 2015-08-03 16:14:47 -10:00
parent 7b1ec6c4b9
commit 6e58666a80
13 changed files with 455 additions and 73 deletions

View File

@ -206,13 +206,51 @@ public:
}
};
/* Resource extractor type */
typedef struct
struct UniqueResult
{
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;
unsigned weight;
} ResExtractor;
};
/* PAKRouter (for detecting shared entry locations) */
template <class BRIDGETYPE>
@ -232,14 +270,17 @@ public:
PAKRouter(const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
: m_gameWorking(working), m_gameCooked(cooked),
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_sharedEntries.clear();
size_t count = 0;
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();
for (const auto& entry : pak.m_idMap)
{
@ -274,7 +315,7 @@ public:
}
HECL::ProjectPath getWorking(const typename BRIDGETYPE::PAKType::Entry* entry,
const ResExtractor& extractor) const
const ResExtractor<BRIDGETYPE>& extractor) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
@ -282,10 +323,11 @@ public:
auto uniqueSearch = m_uniqueEntries.find(entry->id);
if (uniqueSearch != m_uniqueEntries.end())
{
HECL::ProjectPath uniquePath = entry->unique.uniquePath(m_pakWorking);
HECL::SystemString entName = m_pak->bestEntryName(*entry);
if (extractor.fileExt)
entName += extractor.fileExt;
return HECL::ProjectPath(m_pakWorking, entName);
return HECL::ProjectPath(uniquePath, entName);
}
auto sharedSearch = m_sharedEntries.find(entry->id);
if (sharedSearch != m_sharedEntries.end())
@ -295,7 +337,7 @@ public:
entName += extractor.fileExt;
HECL::ProjectPath sharedPath(m_sharedWorking, entName);
HECL::ProjectPath uniquePath(m_pakWorking, entName);
if (extractor.func)
if (extractor.func_a || extractor.func_b)
uniquePath.makeLinkTo(sharedPath);
m_sharedWorking.makeDir();
return sharedPath;
@ -312,7 +354,8 @@ public:
auto uniqueSearch = m_uniqueEntries.find(entry->id);
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);
if (sharedSearch != m_sharedEntries.end())
@ -334,7 +377,7 @@ public:
{
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)
continue;
@ -348,12 +391,20 @@ public:
}
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)
{
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);
}
}

View File

@ -8,8 +8,11 @@ namespace Retro
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);
CMDL::Header head;
@ -30,7 +33,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
/* Open Py Stream */
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
os << "import bmesh\n"
"import bpy;\n";
"import bpy\n"
"bm = bmesh.new()\n";
MaterialSet::RegisterMaterialProps(os);
@ -38,6 +41,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
{
atUint64 secStart = reader.position();
/*
std::unique_ptr<atVec3f[]> vertPos;
std::unique_ptr<atVec3f[]> vertNorm;
typedef atInt16 ShortVec3[3];
@ -45,11 +49,44 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
std::unique_ptr<atVec2f[]> vertUVs;
typedef atInt16 ShortVec2[2];
std::unique_ptr<ShortVec2[]> vertUVsShort;
*/
std::vector<std::vector<unsigned>> matUVCounts;
matUVCounts.reserve(head.matSetCount);
bool visitedDLOffsets = false;
if (s < head.matSetCount)
{
MaterialSet matSet;
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
{
@ -59,31 +96,44 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
{
/* Positions */
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)
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;
}
case 1:
{
/* Normals */
os << "normals = []\n";
if (head.flags.shortNormals())
{
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)
{
vertNormShort[i][0] = reader.readInt16();
vertNormShort[i][1] = reader.readInt16();
vertNormShort[i][2] = reader.readInt16();
//vertNormShort[i][0] = reader.readInt16();
//vertNormShort[i][1] = reader.readInt16();
//vertNormShort[i][2] = reader.readInt16();
os.format("normals.append((%f,%f,%f))\n",
reader.readInt16(), reader.readInt16(), reader.readInt16());
}
}
else
{
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)
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;
}
@ -95,23 +145,30 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
case 3:
{
/* Float UVs */
os << "uv_list = []\n";
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)
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;
}
case 4:
{
/* Short UVs */
os << "suv_list = []\n";
if (head.flags.shortUVs())
{
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)
{
vertUVsShort[i][0] = reader.readInt16();
vertUVsShort[i][1] = reader.readInt16();
os.format("suv_list.append((%f,%f))\n",
reader.readInt16(), reader.readInt16());
}
break;
}
@ -131,7 +188,6 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReade
/* GX Display List (surface) */
SurfaceHeader sHead;
sHead.read(reader);
}
}
}

View File

@ -4,6 +4,7 @@
#include "../DNACommon/DNACommon.hpp"
#include "CMDLMaterials.hpp"
#include "BlenderConnection.hpp"
#include "DNAMP1.hpp"
namespace Retro
{
@ -48,14 +49,18 @@ struct CMDL
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();
if (!conn.createBlend(outPath.getAbsolutePath()))
return false;
return ReadToBlender(conn, rs);
return ReadToBlender(conn, rs, pakRouter);
}
};

View File

@ -18,11 +18,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
HECL::SystemString PAKBridge::getLevelString() const
{
HECL::SystemString retval;
/* Append Level String */
for (const PAK::Entry& entry : m_pak.m_entries)
{
if (entry.type == Retro::MLVL)
@ -36,27 +33,147 @@ HECL::SystemString PAKBridge::getLevelString() const
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
STRG mlvlName;
mlvlName.read(rs);
if (retval.size())
retval += _S(", ");
retval += mlvlName.getSystemString(ENGL, 0);
if (m_levelString.size())
m_levelString += _S(", ");
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;
}
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())
{
case SBIG('STRG'):
return {STRG::Extract, ".yaml"};
return {STRG::Extract, nullptr, ".yaml"};
case SBIG('TXTR'):
return {TXTR::Extract, ".png"};
return {TXTR::Extract, nullptr, ".png"};
case SBIG('CMDL'):
return {CMDL::Extract, ".blend", 1};
return {nullptr, CMDL::Extract, ".blend", 1};
case SBIG('MLVL'):
return {MLVL::Extract, ".yaml"};
return {MLVL::Extract, nullptr, ".yaml"};
}
return {};
}

View File

@ -17,11 +17,26 @@ class PAKBridge
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
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:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
static ResExtractor LookupExtractor(const PAK::Entry& entry);
const std::string& getName() const {return m_node.getName();}
HECL::SystemString getLevelString() const;
void build();
static ResExtractor<PAKBridge> LookupExtractor(const PAK::Entry& entry);
inline const std::string& getName() const {return m_node.getName();}
inline const HECL::SystemString& getLevelString() const {return m_levelString;}
typedef PAK PAKType;
inline const PAKType& getPAK() const {return m_pak;}

View File

@ -34,6 +34,7 @@ struct PAK : BigDNA
UniqueID32 id;
Value<atUint32> size;
Value<atUint32> offset;
UniqueResult unique;
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

View File

@ -4,6 +4,7 @@
#include <unordered_map>
#include "../DNACommon/DNACommon.hpp"
#include "../DNACommon/STRG.hpp"
#include "DNAMP1.hpp"
namespace Retro
{

View File

@ -16,11 +16,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
HECL::SystemString PAKBridge::getLevelString() const
{
HECL::SystemString retval;
/* Append Level String */
for (const DNAMP1::PAK::Entry& entry : m_pak.m_entries)
{
if (entry.type == Retro::MLVL)
@ -34,23 +31,143 @@ HECL::SystemString PAKBridge::getLevelString() const
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
STRG mlvlName;
mlvlName.read(rs);
if (retval.size())
retval += _S(", ");
retval += mlvlName.getSystemString(ENGL, 0);
if (m_levelString.size())
m_levelString += _S(", ");
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;
}
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())
{
case SBIG('STRG'):
return {STRG::Extract, ".as"};
return {STRG::Extract, nullptr, ".as"};
case SBIG('TXTR'):
return {TXTR::Extract, ".png"};
return {TXTR::Extract, nullptr, ".png"};
}
return {};
}

View File

@ -17,11 +17,26 @@ class PAKBridge
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
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:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry);
const std::string& getName() const {return m_node.getName();}
HECL::SystemString getLevelString() const;
void build();
static ResExtractor<PAKBridge> LookupExtractor(const DNAMP1::PAK::Entry& entry);
inline const std::string& getName() const {return m_node.getName();}
inline const HECL::SystemString& getLevelString() const {return m_levelString;}
typedef DNAMP1::PAK PAKType;
inline const PAKType& getPAK() const {return m_pak;}

View File

@ -70,6 +70,7 @@ struct MLVL : BigDNA
String<-1> internalAreaName;
};
Vector<Area, DNA_COUNT(areaCount)> areas;
UniqueID32 worldMap;
Value<atUint8> unknown2;

View File

@ -18,10 +18,8 @@ PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPar
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
HECL::SystemString PAKBridge::getLevelString() const
{
/* Append Level String */
std::set<HECL::SystemString, CaseInsensitiveCompare> uniq;
for (const PAK::Entry& entry : m_pak.m_entries)
{
@ -40,26 +38,28 @@ HECL::SystemString PAKBridge::getLevelString() const
}
}
}
HECL::SystemString retval;
bool comma = false;
for (const HECL::SystemString& str : uniq)
{
if (comma)
retval += _S(", ");
m_levelString += _S(", ");
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())
{
case SBIG('STRG'):
return {STRG::Extract, ".as"};
return {STRG::Extract, nullptr, ".as"};
case SBIG('TXTR'):
return {TXTR::Extract, ".png"};
return {TXTR::Extract, nullptr, ".png"};
}
return {};
}

View File

@ -17,11 +17,13 @@ class PAKBridge
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
PAK m_pak;
HECL::SystemString m_levelString;
public:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
static ResExtractor LookupExtractor(const PAK::Entry& entry);
const std::string& getName() const {return m_node.getName();}
HECL::SystemString getLevelString() const;
void build();
static ResExtractor<PAKBridge> LookupExtractor(const PAK::Entry& entry);
inline const std::string& getName() const {return m_node.getName();}
inline HECL::SystemString getLevelString() const {return m_levelString;}
typedef PAK PAKType;
inline const PAKType& getPAK() const {return m_pak;}

View File

@ -41,6 +41,7 @@ struct PAK : BigDNA
UniqueID64 id;
Value<atUint32> size;
Value<atUint32> offset;
UniqueResult unique;
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