Added support for exporting Trilogy and Wii de Asobu builds

This commit is contained in:
Aruki
2017-07-24 21:08:12 -06:00
parent 305fbbdeed
commit e4d7c37541
13 changed files with 11430 additions and 494 deletions

View File

@@ -17,12 +17,14 @@
#define USE_ASSET_NAME_MAP 1
#define EXPORT_COOKED 1
CGameExporter::CGameExporter(EGame Game, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion)
CGameExporter::CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion)
: mGame(Game)
, mRegion(Region)
, mGameName(rkGameName)
, mGameID(rkGameID)
, mBuildVersion(BuildVersion)
, mDiscType(DiscType)
, mFrontEnd(FrontEnd)
, mpProgress(nullptr)
{
ASSERT(mGame != eUnknownGame);
@@ -96,6 +98,70 @@ void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer)
if (pInst) LoadResource(*pInst, rBuffer);
}
bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
{
if (IsInRoot && mDiscType != eDT_Normal)
{
// Directories - exclude the filesystem for other games
if (pkNode->getKind() == nod::Node::Kind::Directory)
{
// Frontend is always included; this is for compatibility with Dolphin
if (pkNode->getName() == "fe")
return true;
else if (mFrontEnd)
return false;
switch (mGame)
{
case ePrime:
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "MP1JPN") ||
(mDiscType == eDT_Trilogy && pkNode->getName() == "MP1") );
case eEchoes:
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "MP2JPN") ||
(mDiscType == eDT_Trilogy && pkNode->getName() == "MP2") );
case eCorruption:
return (mDiscType == eDT_Trilogy && pkNode->getName() == "MP3");
default:
return false;
}
}
// Files - exclude the DOLs for other games
else
{
// Again - always include frontend. Always include opening.bnr as well.
if (pkNode->getName() == "rs5fe_p.dol" || pkNode->getName() == "opening.bnr")
return true;
else if (mFrontEnd)
return false;
switch (mGame)
{
case ePrime:
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol") ||
(mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp1_p.dol") );
case eEchoes:
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol") ||
(mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp2_p.dol") );
case eCorruption:
return (mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp3_p.dol");
default:
return false;
}
}
}
return true;
}
// ************ PROTECTED ************
bool CGameExporter::ExtractDiscData()
{
@@ -122,7 +188,7 @@ bool CGameExporter::ExtractDiscData()
TString FilesDir = AbsDiscDir + "files/";
FileUtil::MakeDirectory(FilesDir);
bool Success = ExtractDiscNodeRecursive(&pDataPartition->getFSTRoot(), FilesDir, Context);
bool Success = ExtractDiscNodeRecursive(&pDataPartition->getFSTRoot(), FilesDir, true, Context);
if (!Success) return false;
if (!mpProgress->ShouldCancel())
@@ -150,18 +216,25 @@ bool CGameExporter::ExtractDiscData()
return false;
}
bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, const nod::ExtractionContext& rkContext)
bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, bool RootNode, const nod::ExtractionContext& rkContext)
{
for (nod::Node::DirectoryIterator Iter = pkNode->begin(); Iter != pkNode->end(); ++Iter)
{
if (!ShouldExportDiscNode(&*Iter, RootNode))
continue;
if (Iter->getKind() == nod::Node::Kind::File)
{
TString FilePath = rkDir + Iter->getName();
bool Success = Iter->extractToDirectory(*rkDir.ToUTF16(), rkContext);
if (!Success) return false;
if (FilePath.GetFileExtension() == "pak")
mPaks.push_back(FilePath);
if (FilePath.GetFileExtension().CaseInsensitiveCompare("pak"))
{
// For multi-game Wii discs, don't track packages for frontend unless we're exporting frontend
if (mDiscType == eDT_Normal || mFrontEnd || pkNode->getName() != "fe")
mPaks.push_back(FilePath);
}
}
else
@@ -170,7 +243,7 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
bool Success = FileUtil::MakeDirectory(Subdir);
if (!Success) return false;
Success = ExtractDiscNodeRecursive(&*Iter, Subdir, rkContext);
Success = ExtractDiscNodeRecursive(&*Iter, Subdir, false, rkContext);
if (!Success) return false;
}
}

View File

@@ -12,6 +12,13 @@
#include <map>
#include <nod/nod.hpp>
enum EDiscType
{
eDT_Normal,
eDT_WiiDeAsobu,
eDT_Trilogy
};
class CGameExporter
{
// Project Data
@@ -33,6 +40,8 @@ class CGameExporter
// Files
nod::DiscBase *mpDisc;
EDiscType mDiscType;
bool mFrontEnd;
// Resources
TStringList mPaks;
@@ -65,15 +74,16 @@ class CGameExporter
};
public:
CGameExporter(EGame Game, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress);
void LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer);
bool ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot);
inline TString ProjectPath() const { return mProjectPath; }
protected:
bool ExtractDiscData();
bool ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, const nod::ExtractionContext& rkContext);
bool ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, bool RootNode, const nod::ExtractionContext& rkContext);
void LoadPaks();
void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer);
void ExportCookedResources();

View File

@@ -100,6 +100,7 @@ public:
inline float BuildVersion() const { return mBuildVersion; }
inline bool IsWiiBuild() const { return mBuildVersion >= 3.f; }
inline bool IsTrilogy() const { return mGame <= eCorruption && mBuildVersion >= 3.593f; }
inline bool IsWiiDeAsobu() const { return mGame < eCorruption && mBuildVersion >= 3.f && mBuildVersion < 3.593f; }
};
#endif // CGAMEPROJECT_H

View File

@@ -170,9 +170,14 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
{
// Create new subdirectory
pSubdir = new CVirtualDirectory(this, DirName, mpStore);
FileUtil::MakeDirectory(mpStore->ResourcesDir() + pSubdir->FullPath());
mSubdirectories.push_back(pSubdir);
if (!pSubdir->CreateFilesystemDirectory())
{
delete pSubdir;
return false;
}
mSubdirectories.push_back(pSubdir);
std::sort(mSubdirectories.begin(), mSubdirectories.end(), [](CVirtualDirectory *pLeft, CVirtualDirectory *pRight) -> bool {
return (pLeft->Name().ToUpper() < pRight->Name().ToUpper());
});
@@ -184,6 +189,13 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
for (auto Iter = Components.begin(); Iter != Components.end(); Iter++)
{
pSubdir = new CVirtualDirectory(pSubdir, *Iter, mpStore);
if (!pSubdir->CreateFilesystemDirectory())
{
delete pSubdir;
return false;
}
pSubdir->Parent()->mSubdirectories.push_back(pSubdir);
}
@@ -307,6 +319,23 @@ void CVirtualDirectory::DeleteEmptySubdirectories()
}
}
bool CVirtualDirectory::CreateFilesystemDirectory()
{
TString AbsPath = AbsolutePath();
if (!FileUtil::Exists(AbsPath))
{
bool CreateSuccess = FileUtil::MakeDirectory(AbsPath);
if (!CreateSuccess)
Log::Error("FAILED to create filesystem directory: " + AbsPath);
return CreateSuccess;
}
return true;
}
bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
{
ASSERT(!pParent->IsDescendantOf(this));

View File

@@ -39,6 +39,7 @@ public:
bool Rename(const TString& rkNewName);
bool Delete();
void DeleteEmptySubdirectories();
bool CreateFilesystemDirectory();
bool SetParent(CVirtualDirectory *pParent);
static bool IsValidDirectoryName(const TString& rkName);