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 <Athena/DNA.hpp>
#include "HECL/HECL.hpp" #include "HECL/HECL.hpp"
#include "HECL/Database.hpp"
namespace Retro 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 */ /* Language-identifiers */
extern const HECL::FourCC ENGL; extern const HECL::FourCC ENGL;
extern const HECL::FourCC FREN; extern const HECL::FourCC FREN;

View File

@ -6,6 +6,7 @@
#include <angelscript.h> #include <angelscript.h>
#include <HECL/HECL.hpp> #include <HECL/HECL.hpp>
#include <HECL/Database.hpp> #include <HECL/Database.hpp>
#include <Athena/FileWriter.hpp>
#include "DNACommon.hpp" #include "DNACommon.hpp"
namespace Retro namespace Retro
@ -22,6 +23,29 @@ struct ISTRG
virtual bool readAngelScript(const AngelScript::asIScriptModule& in)=0; virtual bool readAngelScript(const AngelScript::asIScriptModule& in)=0;
virtual void writeAngelScript(std::ofstream& out) const=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); std::unique_ptr<ISTRG> LoadSTRG(Athena::io::IStreamReader& reader);

View File

@ -1,9 +1,67 @@
#define NOD_ATHENA 1
#include "DNAMP1.hpp" #include "DNAMP1.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro namespace Retro
{ {
namespace DNAMP1 namespace DNAMP1
{ {
LogVisor::LogModule Log("Retro::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__ #define __DNAMP1_HPP__
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
#include "PAK.hpp"
namespace Retro namespace Retro
{ {
@ -10,6 +11,22 @@ namespace DNAMP1
extern LogVisor::LogModule Log; 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 result->second;
return nullptr; 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); bool readAngelScript(const AngelScript::asIScriptModule& in);
void writeAngelScript(std::ofstream& out) const; void writeAngelScript(std::ofstream& out) const;
}; };
} }

View File

@ -1,9 +1,68 @@
#define NOD_ATHENA 1
#include "DNAMP2.hpp" #include "DNAMP2.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro namespace Retro
{ {
namespace DNAMP2 namespace DNAMP2
{ {
LogVisor::LogModule Log("Retro::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__ #define __DNAMP2_HPP__
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
#include "../DNAMP1/PAK.hpp"
namespace Retro namespace Retro
{ {
@ -10,6 +11,22 @@ namespace DNAMP2
extern LogVisor::LogModule Log; 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 "DNAMP3.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
namespace Retro namespace Retro
{ {
namespace DNAMP3 namespace DNAMP3
{ {
LogVisor::LogModule Log("Retro::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__ #define __DNAMP3_HPP__
#include "../DNACommon/DNACommon.hpp" #include "../DNACommon/DNACommon.hpp"
#include "PAK.hpp"
namespace Retro namespace Retro
{ {
@ -10,6 +11,22 @@ namespace DNAMP3
extern LogVisor::LogModule Log; 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 result->second;
return nullptr; 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 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; bool isWii;
m_disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), 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) if (standalone)
return checkFromStandaloneDisc(*m_disc.get(), *regstr, info.extractArgs, reps); return checkFromStandaloneDisc(project, *m_disc.get(), *regstr, info.extractArgs, reps);
else 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) bool SpecBase::canCook(const HECL::Database::Project& project, const CookTaskInfo& info)

View File

@ -11,8 +11,9 @@ namespace Retro
struct SpecBase : HECL::Database::IDataSpec struct SpecBase : HECL::Database::IDataSpec
{ {
bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps); bool canExtract(HECL::Database::Project& project, const ExtractPassInfo& info,
void doExtract(const 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); bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info);
void doCook(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); void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
virtual bool checkStandaloneID(const char* id) const=0; 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 HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)=0; 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 HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps)=0; 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 checkFromProject(HECL::Database::Project& proj)=0;
virtual bool readFromProject(HECL::Database::Project& proj)=0; virtual bool readFromProject(HECL::Database::Project& proj)=0;

View File

@ -1,11 +1,8 @@
#include <utility> #include <utility>
#include <stdio.h> #include <stdio.h>
#define NOD_ATHENA 1
#include "SpecBase.hpp" #include "SpecBase.hpp"
#include "DNAMP1/PAK.hpp" #include "DNAMP1/DNAMP1.hpp"
#include "DNAMP1/MLVL.hpp"
#include "DNAMP1/STRG.hpp"
namespace Retro namespace Retro
{ {
@ -21,16 +18,11 @@ struct SpecMP1 : SpecBase
return false; return false;
} }
struct DiscPAK std::vector<DNAMP1::PAKBridge> m_paks;
{ std::map<std::string, DNAMP1::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
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;
void buildPaks(NOD::DiscBase::IPartition::Node& root, void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
ExtractReport& rep) ExtractReport& rep)
{ {
@ -83,51 +75,29 @@ struct SpecMP1 : SpecBase
} }
if (good) if (good)
{ m_paks.emplace_back(project, child);
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
} }
} }
} }
/* Sort PAKs alphabetically */ /* Sort PAKs alphabetically */
m_orderedPaks.clear(); m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks) for (DNAMP1::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak; m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */ /* 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(); rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back(); ExtractReport& childRep = rep.childOpts.back();
childRep.name = item.first; childRep.name = item.first;
childRep.desc = item.second->getLevelString();
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);
}
}
}
} }
} }
bool checkFromStandaloneDisc(NOD::DiscBase& disc, bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr, const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -150,12 +120,13 @@ struct SpecMP1 : SpecBase
/* Iterate PAKs and build level options */ /* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot(); NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep); buildPaks(project, root, args, rep);
return true; return true;
} }
bool checkFromTrilogyDisc(NOD::DiscBase& disc, bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr, const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -204,37 +175,23 @@ struct SpecMP1 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp1It = root.find("MP1"); NOD::DiscBase::IPartition::Node::DirectoryIterator mp1It = root.find("MP1");
if (mp1It == root.end()) if (mp1It == root.end())
return false; return false;
buildPaks(*mp1It, mp1args, rep); buildPaks(project, *mp1It, mp1args, rep);
return true; 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"); 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::const_iterator extit = name.end() - 4;
std::string baseName(name.begin(), extit); std::string baseName(name.begin(), extit);
HECL::ProjectPath pakPath(mp1Path, baseName); HECL::ProjectPath pakPath(mp1Path, baseName);
pak.extractResources(pakPath);
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);
}
}
} }
return true; return true;

View File

@ -1,10 +1,7 @@
#include <utility> #include <utility>
#define NOD_ATHENA 1
#include "SpecBase.hpp" #include "SpecBase.hpp"
#include "DNAMP1/PAK.hpp" #include "DNAMP2/DNAMP2.hpp"
#include "DNAMP2/MLVL.hpp"
#include "DNAMP2/STRG.hpp"
namespace Retro namespace Retro
{ {
@ -20,16 +17,11 @@ struct SpecMP2 : SpecBase
return false; return false;
} }
struct DiscPAK std::vector<DNAMP2::PAKBridge> m_paks;
{ std::map<std::string, DNAMP2::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
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;
void buildPaks(NOD::DiscBase::IPartition::Node& root, void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
ExtractReport& rep) ExtractReport& rep)
{ {
@ -82,51 +74,28 @@ struct SpecMP2 : SpecBase
} }
if (good) if (good)
{ m_paks.emplace_back(project, child);
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
} }
} }
} }
/* Sort PAKs alphabetically */ /* Sort PAKs alphabetically */
m_orderedPaks.clear(); m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks) for (DNAMP2::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak; m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */ /* 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(); rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back(); ExtractReport& childRep = rep.childOpts.back();
childRep.name = item.first; childRep.name = item.first;
childRep.desc = item.second->getLevelString();
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);
}
}
}
} }
} }
bool checkFromStandaloneDisc(NOD::DiscBase& disc, bool checkFromStandaloneDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr, const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -149,12 +118,13 @@ struct SpecMP2 : SpecBase
/* Iterate PAKs and build level options */ /* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot(); NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep); buildPaks(project, root, args, rep);
return true; return true;
} }
bool checkFromTrilogyDisc(NOD::DiscBase& disc, bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr, const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -203,12 +173,12 @@ struct SpecMP2 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp2It = root.find("MP2"); NOD::DiscBase::IPartition::Node::DirectoryIterator mp2It = root.find("MP2");
if (mp2It == root.end()) if (mp2It == root.end())
return false; return false;
buildPaks(*mp2It, mp2args, rep); buildPaks(project, *mp2It, mp2args, rep);
return true; 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 <utility>
#include <set> #include <set>
#define NOD_ATHENA 1
#include "SpecBase.hpp" #include "SpecBase.hpp"
#include "DNAMP3/PAK.hpp" #include "DNAMP3/DNAMP3.hpp"
#include "DNAMP3/MLVL.hpp"
#include "DNAMP3/STRG.hpp"
namespace Retro namespace Retro
{ {
@ -21,16 +18,11 @@ struct SpecMP3 : SpecBase
return false; return false;
} }
struct DiscPAK std::vector<DNAMP3::PAKBridge> m_paks;
{ std::map<std::string, DNAMP3::PAKBridge*, CaseInsensitiveCompare> m_orderedPaks;
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;
void buildPaks(NOD::DiscBase::IPartition::Node& root, void buildPaks(HECL::Database::Project& project,
NOD::DiscBase::IPartition::Node& root,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
ExtractReport& rep) ExtractReport& rep)
{ {
@ -83,22 +75,18 @@ struct SpecMP3 : SpecBase
} }
if (good) if (good)
{ m_paks.emplace_back(project, child);
m_paks.emplace_back(child);
NOD::AthenaPartReadStream rs(child.beginReadStream());
m_paks.back().pak.read(rs);
}
} }
} }
} }
/* Sort PAKs alphabetically */ /* Sort PAKs alphabetically */
m_orderedPaks.clear(); m_orderedPaks.clear();
for (DiscPAK& dpak : m_paks) for (DNAMP3::PAKBridge& dpak : m_paks)
m_orderedPaks[dpak.node.getName()] = &dpak; m_orderedPaks[dpak.getName()] = &dpak;
/* Assemble extract report */ /* 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(); rep.childOpts.emplace_back();
ExtractReport& childRep = rep.childOpts.back(); ExtractReport& childRep = rep.childOpts.back();
@ -111,37 +99,12 @@ struct SpecMP3 : SpecBase
childRep.desc = _S("Phaaze"); childRep.desc = _S("Phaaze");
continue; continue;
} }
childRep.desc = item.second->getLevelString();
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));
}
}
}
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 HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -164,12 +127,13 @@ struct SpecMP3 : SpecBase
/* Iterate PAKs and build level options */ /* Iterate PAKs and build level options */
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot(); NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
buildPaks(root, args, rep); buildPaks(project, root, args, rep);
return true; return true;
} }
bool checkFromTrilogyDisc(NOD::DiscBase& disc, bool checkFromTrilogyDisc(HECL::Database::Project& project,
NOD::DiscBase& disc,
const HECL::SystemString& regstr, const HECL::SystemString& regstr,
const std::vector<HECL::SystemString>& args, const std::vector<HECL::SystemString>& args,
std::vector<ExtractReport>& reps) std::vector<ExtractReport>& reps)
@ -218,12 +182,12 @@ struct SpecMP3 : SpecBase
NOD::DiscBase::IPartition::Node::DirectoryIterator mp3It = root.find("MP3"); NOD::DiscBase::IPartition::Node::DirectoryIterator mp3It = root.find("MP3");
if (mp3It == root.end()) if (mp3It == root.end())
return false; return false;
buildPaks(*mp3It, mp3args, rep); buildPaks(project, *mp3It, mp3args, rep);
return true; 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