re-balancing of DataSpec/DNA systems

This commit is contained in:
Jack Andersen 2015-07-16 14:01:05 -10:00
parent 94a6707dd3
commit 94d84d8991
17 changed files with 364 additions and 175 deletions

View File

@ -3,6 +3,7 @@
#include <Athena/DNA.hpp>
#include "HECL/HECL.hpp"
#include "HECL/Database.hpp"
namespace Retro
{
@ -178,6 +179,16 @@ public:
}
};
/* Resource extractor type */
typedef struct
{
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func;
const char* fileExt;
} ResExtractor;
/* Resource cooker function */
typedef std::function<bool(const HECL::ProjectPath&, const HECL::ProjectPath&)> ResCooker;
/* Language-identifiers */
extern const HECL::FourCC ENGL;
extern const HECL::FourCC FREN;

View File

@ -6,6 +6,7 @@
#include <angelscript.h>
#include <HECL/HECL.hpp>
#include <HECL/Database.hpp>
#include <Athena/FileWriter.hpp>
#include "DNACommon.hpp"
namespace Retro
@ -22,6 +23,29 @@ struct ISTRG
virtual bool readAngelScript(const AngelScript::asIScriptModule& in)=0;
virtual void writeAngelScript(std::ofstream& out) const=0;
template <class SUBCLS>
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
{
SUBCLS strg;
strg.read(rs);
std::ofstream strgOut(outPath.getAbsolutePath());
strg.writeAngelScript(strgOut);
return true;
}
template <class SUBCLS>
static bool Cook(const HECL::ProjectPath& inPath, const HECL::ProjectPath& outPath)
{
SUBCLS strg;
HECL::Database::ASUniqueModule mod = HECL::Database::ASUniqueModule::CreateFromPath(inPath);
if (!mod)
return false;
strg.readAngelScript(mod);
Athena::io::FileWriter ws(outPath.getAbsolutePath());
strg.write(ws);
return true;
}
};
std::unique_ptr<ISTRG> LoadSTRG(Athena::io::IStreamReader& reader);

View File

@ -1,9 +1,67 @@
#define NOD_ATHENA 1
#include "DNAMP1.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro
{
namespace DNAMP1
{
LogVisor::LogModule Log("Retro::DNAMP1");
PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node)
: m_project(project), m_node(node)
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
std::string PAKBridge::getLevelString() const
{
std::string retval;
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);
const PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
STRG mlvlName;
mlvlName.read(rs);
if (retval.size())
retval += _S(", ");
retval += mlvlName.getSystemString(ENGL, 0);
}
}
}
return retval;
}
ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
{
if (entry.type == Retro::STRG)
return {STRG::Extract<STRG>, ".strg"};
return {};
}
bool PAKBridge::extractResources(const HECL::ProjectPath& dirOut)
{
for (const std::pair<UniqueID32, PAK::Entry*>& item : m_pak.m_idMap)
{
ResExtractor extractor = LookupExtractor(*item.second);
if (extractor.func)
{
PAKEntryReadStream strgIn = item.second->beginReadStream(m_node);
HECL::ProjectPath resPath(dirOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
extractor.func(strgIn, resPath);
}
}
return true;
}
}
}

View File

@ -2,6 +2,7 @@
#define __DNAMP1_HPP__
#include "../DNACommon/DNACommon.hpp"
#include "PAK.hpp"
namespace Retro
{
@ -10,6 +11,22 @@ namespace DNAMP1
extern LogVisor::LogModule Log;
/* MP1-specific, one-shot PAK traversal/extraction class */
class PAKBridge
{
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
PAK m_pak;
static ResExtractor LookupExtractor(const PAK::Entry& entry);
public:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
const std::string& getName() const {return m_node.getName();}
std::string getLevelString() const;
bool extractResources(const HECL::ProjectPath& dirOut);
};
}
}

View File

@ -61,6 +61,17 @@ struct PAK : BigDNA
return result->second;
return nullptr;
}
inline std::string bestEntryName(const Entry& entry) const
{
/* Prefer named entries first */
for (const NameEntry& nentry : m_nameEntries)
if (nentry.id == entry.id)
return nentry.name;
/* Otherwise return ID format string */
return entry.id.toString();
}
};
}

View File

@ -57,6 +57,8 @@ struct STRG : ISTRG, BigDNA
bool readAngelScript(const AngelScript::asIScriptModule& in);
void writeAngelScript(std::ofstream& out) const;
};
}

View File

@ -1,9 +1,68 @@
#define NOD_ATHENA 1
#include "DNAMP2.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro
{
namespace DNAMP2
{
LogVisor::LogModule Log("Retro::DNAMP2");
PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node)
: m_project(project), m_node(node)
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
std::string PAKBridge::getLevelString() const
{
std::string retval;
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);
const DNAMP1::PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
STRG mlvlName;
mlvlName.read(rs);
if (retval.size())
retval += _S(", ");
retval += mlvlName.getSystemString(ENGL, 0);
}
}
}
return retval;
}
ResExtractor PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& entry)
{
if (entry.type == Retro::STRG)
return {STRG::Extract<STRG>, ".strg"};
return {};
}
bool PAKBridge::extractResources(const HECL::ProjectPath& dirOut)
{
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry*>& item : m_pak.m_idMap)
{
ResExtractor extractor = LookupExtractor(*item.second);
if (extractor.func)
{
PAKEntryReadStream strgIn = item.second->beginReadStream(m_node);
HECL::ProjectPath resPath(dirOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
extractor.func(strgIn, resPath);
}
}
return true;
}
}
}

View File

@ -2,6 +2,7 @@
#define __DNAMP2_HPP__
#include "../DNACommon/DNACommon.hpp"
#include "../DNAMP1/PAK.hpp"
namespace Retro
{
@ -10,6 +11,22 @@ namespace DNAMP2
extern LogVisor::LogModule Log;
/* MP2-specific, one-shot PAK traversal/extraction class */
class PAKBridge
{
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
DNAMP1::PAK m_pak;
static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry);
public:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
const std::string& getName() const {return m_node.getName();}
std::string getLevelString() const;
bool extractResources(const HECL::ProjectPath& dirOut);
};
}
}

View File

@ -1,9 +1,76 @@
#include <set>
#define NOD_ATHENA 1
#include "DNAMP3.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro
{
namespace DNAMP3
{
LogVisor::LogModule Log("Retro::DNAMP3");
PAKBridge::PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node)
: m_project(project), m_node(node)
{
NOD::AthenaPartReadStream rs(node.beginReadStream());
m_pak.read(rs);
}
std::string PAKBridge::getLevelString() const
{
std::string retval;
std::set<HECL::SystemString> worldNames;
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);
const PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
STRG mlvlName;
mlvlName.read(rs);
worldNames.emplace(mlvlName.getSystemString(ENGL, 0));
}
}
}
for (const std::string& name : worldNames)
{
if (retval.size())
retval += _S(", ");
retval += name;
}
return retval;
}
ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry)
{
if (entry.type == Retro::STRG)
return {STRG::Extract<STRG>, ".strg"};
return {};
}
bool PAKBridge::extractResources(const HECL::ProjectPath& dirOut)
{
for (const std::pair<UniqueID64, PAK::Entry*>& item : m_pak.m_idMap)
{
ResExtractor extractor = LookupExtractor(*item.second);
if (extractor.func)
{
PAKEntryReadStream strgIn = item.second->beginReadStream(m_node);
HECL::ProjectPath resPath(dirOut, m_pak.bestEntryName(*item.second) + extractor.fileExt);
extractor.func(strgIn, resPath);
}
}
return true;
}
}
}

View File

@ -2,6 +2,7 @@
#define __DNAMP3_HPP__
#include "../DNACommon/DNACommon.hpp"
#include "PAK.hpp"
namespace Retro
{
@ -10,6 +11,22 @@ namespace DNAMP3
extern LogVisor::LogModule Log;
/* MP3-specific, one-shot PAK traversal/extraction class */
class PAKBridge
{
HECL::Database::Project& m_project;
const NOD::DiscBase::IPartition::Node& m_node;
PAK m_pak;
static ResExtractor LookupExtractor(const PAK::Entry& entry);
public:
PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node);
const std::string& getName() const {return m_node.getName();}
std::string getLevelString() const;
bool extractResources(const HECL::ProjectPath& dirOut);
};
}
}

View File

@ -72,6 +72,17 @@ struct PAK : BigDNA
return result->second;
return nullptr;
}
inline std::string bestEntryName(const Entry& entry) const
{
/* Prefer named entries first */
for (const NameEntry& nentry : m_nameEntries)
if (nentry.id == entry.id)
return nentry.name;
/* Otherwise return ID format string */
return entry.id.toString();
}
};
}

View File

@ -3,7 +3,8 @@
namespace Retro
{
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
bool SpecBase::canExtract(HECL::Database::Project& project,
const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
{
bool isWii;
m_disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), isWii);
@ -38,14 +39,14 @@ bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport
}
if (standalone)
return checkFromStandaloneDisc(*m_disc.get(), *regstr, info.extractArgs, reps);
return checkFromStandaloneDisc(project, *m_disc.get(), *regstr, info.extractArgs, reps);
else
return checkFromTrilogyDisc(*m_disc.get(), *regstr, info.extractArgs, reps);
return checkFromTrilogyDisc(project, *m_disc.get(), *regstr, info.extractArgs, reps);
}
void SpecBase::doExtract(const HECL::Database::Project& project, const ExtractPassInfo&)
void SpecBase::doExtract(HECL::Database::Project& project, const ExtractPassInfo&)
{
extractFromDisc(*m_disc.get(), project);
extractFromDisc(project, *m_disc.get());
}
bool SpecBase::canCook(const HECL::Database::Project& project, const CookTaskInfo& info)

View File

@ -11,8 +11,9 @@ namespace Retro
struct SpecBase : HECL::Database::IDataSpec
{
bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps);
void doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info);
bool canExtract(HECL::Database::Project& project, const ExtractPassInfo& info,
std::vector<ExtractReport>& reps);
void doExtract(HECL::Database::Project& project, const ExtractPassInfo& info);
bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info);
void doCook(const HECL::Database::Project& project, const CookTaskInfo& info);
@ -23,15 +24,17 @@ struct SpecBase : HECL::Database::IDataSpec
void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
virtual bool checkStandaloneID(const char* id) const=0;
virtual bool checkFromStandaloneDisc(NOD::DiscBase& disc,
virtual bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)=0;
virtual bool checkFromTrilogyDisc(NOD::DiscBase& disc,
virtual bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)=0;
virtual bool extractFromDisc(NOD::DiscBase& disc, const HECL::Database::Project& project)=0;
virtual bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase& disc)=0;
virtual bool checkFromProject(HECL::Database::Project& proj)=0;
virtual bool readFromProject(HECL::Database::Project& proj)=0;

View File

@ -1,11 +1,8 @@
#include <utility>
#include <stdio.h>
#define NOD_ATHENA 1
#include "SpecBase.hpp"
#include "DNAMP1/PAK.hpp"
#include "DNAMP1/MLVL.hpp"
#include "DNAMP1/STRG.hpp"
#include "DNAMP1/DNAMP1.hpp"
namespace Retro
{
@ -21,16 +18,11 @@ struct SpecMP1 : SpecBase
return false;
}
struct DiscPAK
{
const NOD::DiscBase::IPartition::Node& node;
DNAMP1::PAK pak;
DiscPAK(const NOD::DiscBase::IPartition::Node& n) : node(n) {}
};
std::vector<DiscPAK> m_paks;
std::map<std::string, DiscPAK*, CaseInsensitiveCompare> m_orderedPaks;
std::vector<DNAMP1::PAKBridge> m_paks;
std::map<std::string, DNAMP1::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
void buildPaks(NOD::DiscBase::IPartition::Node& root,
void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args,
ExtractReport& rep)
{
@ -83,51 +75,29 @@ struct SpecMP1 : SpecBase
}
if (good)
{
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
m_paks.emplace_back(project, child);
}
}
}
/* Sort PAKs alphabetically */
m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak;
for (DNAMP1::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */
for (const std::pair<std::string, DiscPAK*>& item : m_orderedPaks)
for (const std::pair<std::string, DNAMP1::PAKBridge*>& item : m_orderedPaks)
{
rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back();
childRep.name = item.first;
DNAMP1::PAK& pak = item.second->pak;
for (DNAMP1::PAK::Entry& entry : pak.m_entries)
{
if (entry.type == MLVL)
{
PAKEntryReadStream rs = entry.beginReadStream(item.second->node);
DNAMP1::MLVL mlvl;
mlvl.read(rs);
const DNAMP1::PAK::Entry* nameEnt = pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(item.second->node);
DNAMP1::STRG mlvlName;
mlvlName.read(rs);
if (childRep.desc.size())
childRep.desc += _S(", ");
childRep.desc += mlvlName.getSystemString(ENGL, 0);
}
}
}
childRep.desc = item.second->getLevelString();
}
}
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -150,12 +120,13 @@ struct SpecMP1 : SpecBase
/* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep);
buildPaks(project, root, args, rep);
return true;
}
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -204,37 +175,23 @@ struct SpecMP1 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp1It = root.find("MP1");
if (mp1It == root.end())
return false;
buildPaks(*mp1It, mp1args, rep);
buildPaks(project, *mp1It, mp1args, rep);
return true;
}
bool extractFromDisc(NOD::DiscBase& disc, const HECL::Database::Project& project)
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase& disc)
{
HECL::ProjectPath mp1Path(project.getProjectRootPath(), "MP1");
for (const DiscPAK& pak : m_paks)
for (DNAMP1::PAKBridge& pak : m_paks)
{
const std::string& name = pak.node.getName();
const std::string& name = pak.getName();
std::string::const_iterator extit = name.end() - 4;
std::string baseName(name.begin(), extit);
HECL::ProjectPath pakPath(mp1Path, baseName);
for (const std::pair<UniqueID32, DNAMP1::PAK::Entry*>& item : pak.pak.m_idMap)
{
if (item.second->type == STRG)
{
DNAMP1::STRG strg;
PAKEntryReadStream strgIn = item.second->beginReadStream(pak.node);
strg.read(strgIn);
HECL::SystemChar strgPath[1024];
HECL::SNPrintf(strgPath, 1024, _S("%s/%08X.strg"), pakPath.getAbsolutePath().c_str(), item.second->id.toUint32());
std::ofstream strgOut(strgPath);
strg.writeAngelScript(strgOut);
}
}
pak.extractResources(pakPath);
}
return true;

View File

@ -1,10 +1,7 @@
#include <utility>
#define NOD_ATHENA 1
#include "SpecBase.hpp"
#include "DNAMP1/PAK.hpp"
#include "DNAMP2/MLVL.hpp"
#include "DNAMP2/STRG.hpp"
#include "DNAMP2/DNAMP2.hpp"
namespace Retro
{
@ -20,16 +17,11 @@ struct SpecMP2 : SpecBase
return false;
}
struct DiscPAK
{
const NOD::DiscBase::IPartition::Node& node;
DNAMP1::PAK pak;
DiscPAK(const NOD::DiscBase::IPartition::Node& n) : node(n) {}
};
std::vector<DiscPAK> m_paks;
std::map<std::string, DiscPAK*, CaseInsensitiveCompare> m_orderedPaks;
std::vector<DNAMP2::PAKBridge> m_paks;
std::map<std::string, DNAMP2::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
void buildPaks(NOD::DiscBase::IPartition::Node& root,
void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args,
ExtractReport& rep)
{
@ -82,51 +74,28 @@ struct SpecMP2 : SpecBase
}
if (good)
{
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
m_paks.emplace_back(project, child);
}
}
}
/* Sort PAKs alphabetically */
m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak;
for (DNAMP2::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */
for (const std::pair<std::string, DiscPAK*>& item : m_orderedPaks)
for (const std::pair<std::string, DNAMP2::PAKBridge*>& item : m_orderedPaks)
{
rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back();
childRep.name = item.first;
DNAMP1::PAK& pak = item.second->pak;
for (DNAMP1::PAK::Entry& entry : pak.m_entries)
{
if (entry.type == MLVL)
{
PAKEntryReadStream rs = entry.beginReadStream(item.second->node);
DNAMP2::MLVL mlvl;
mlvl.read(rs);
const DNAMP1::PAK::Entry* nameEnt = pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(item.second->node);
DNAMP2::STRG mlvlName;
mlvlName.read(rs);
if (childRep.desc.size())
childRep.desc += _S(", ");
childRep.desc += mlvlName.getSystemString(ENGL, 0);
}
}
}
childRep.desc = item.second->getLevelString();
}
}
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -149,12 +118,13 @@ struct SpecMP2 : SpecBase
/* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep);
buildPaks(project, root, args, rep);
return true;
}
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -203,12 +173,12 @@ struct SpecMP2 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp2It = root.find("MP2");
if (mp2It == root.end())
return false;
buildPaks(*mp2It, mp2args, rep);
buildPaks(project, *mp2It, mp2args, rep);
return true;
}
bool extractFromDisc(NOD::DiscBase& disc, const HECL::Database::Project& project)
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase& disc)
{
}

View File

@ -1,11 +1,8 @@
#include <utility>
#include <set>
#define NOD_ATHENA 1
#include "SpecBase.hpp"
#include "DNAMP3/PAK.hpp"
#include "DNAMP3/MLVL.hpp"
#include "DNAMP3/STRG.hpp"
#include "DNAMP3/DNAMP3.hpp"
namespace Retro
{
@ -21,16 +18,11 @@ struct SpecMP3 : SpecBase
return false;
}
struct DiscPAK
{
const NOD::DiscBase::IPartition::Node& node;
DNAMP3::PAK pak;
DiscPAK(const NOD::DiscBase::IPartition::Node& n) : node(n) {}
};
std::vector<DiscPAK> m_paks;
std::map<std::string, DiscPAK*, CaseInsensitiveCompare> m_orderedPaks;
std::vector<DNAMP3::PAKBridge> m_paks;
std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
void buildPaks(NOD::DiscBase::IPartition::Node& root,
void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args,
ExtractReport& rep)
{
@ -83,22 +75,18 @@ struct SpecMP3 : SpecBase
}
if (good)
{
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
m_paks.emplace_back(project, child);
}
}
}
/* Sort PAKs alphabetically */
m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak;
for (DNAMP3::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */
for (const std::pair<std::string, DiscPAK*>& item : m_orderedPaks)
for (const std::pair<std::string, DNAMP3::PAKBridge*>& item : m_orderedPaks)
{
rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back();
@ -111,37 +99,12 @@ struct SpecMP3 : SpecBase
childRep.desc = _S("Phaaze");
continue;
}
std::set<HECL::SystemString> worldNames;
DNAMP3::PAK& pak = item.second->pak;
for (DNAMP3::PAK::Entry& entry : pak.m_entries)
{
if (entry.type == MLVL)
{
PAKEntryReadStream rs = entry.beginReadStream(item.second->node);
DNAMP3::MLVL mlvl;
mlvl.read(rs);
const DNAMP3::PAK::Entry* nameEnt = pak.lookupEntry(mlvl.worldNameId);
if (nameEnt)
{
PAKEntryReadStream rs = nameEnt->beginReadStream(item.second->node);
DNAMP3::STRG mlvlName;
mlvlName.read(rs);
worldNames.emplace(mlvlName.getSystemString(ENGL, 0));
}
childRep.desc = item.second->getLevelString();
}
}
for (const std::string& name : worldNames)
{
if (childRep.desc.size())
childRep.desc += _S(", ");
childRep.desc += name;
}
}
}
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -164,12 +127,13 @@ struct SpecMP3 : SpecBase
/* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep);
buildPaks(project, root, args, rep);
return true;
}
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)
@ -218,12 +182,12 @@ struct SpecMP3 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp3It = root.find("MP3");
if (mp3It == root.end())
return false;
buildPaks(*mp3It, mp3args, rep);
buildPaks(project, *mp3It, mp3args, rep);
return true;
}
bool extractFromDisc(NOD::DiscBase& disc, const HECL::Database::Project& project)
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase& disc)
{
}

2
NODLib

@ -1 +1 @@
Subproject commit cbea8fe76471e19b7b98190b56932a2c369fefd8
Subproject commit bcf67ca8eb94acbf3834fe01de033a4382626a13