Added support for CAUD dependencies, dropped redundant asset ID in dependency trees, various MP3 fixes

This commit is contained in:
Aruki
2017-02-20 03:42:04 -07:00
parent 5485d42b56
commit a88afe31e3
40 changed files with 370 additions and 755 deletions

View File

@@ -1,6 +1,7 @@
#include "AssetNameGeneration.h"
#include "CGameProject.h"
#include "CResourceIterator.h"
#include "Core/Resource/CAudioMacro.h"
#include "Core/Resource/CFont.h"
#include "Core/Resource/CScan.h"
#include "Core/Resource/CWorld.h"
@@ -12,6 +13,7 @@
#define PROCESS_AREAS 1
#define PROCESS_MODELS 1
#define PROCESS_AUDIO_GROUPS 1
#define PROCESS_AUDIO_MACROS 1
#define PROCESS_ANIM_CHAR_SETS 1
#define PROCESS_STRINGS 1
#define PROCESS_SCANS 1
@@ -19,10 +21,16 @@
void ApplyGeneratedName(CResourceEntry *pEntry, const TWideString& rkDir, const TWideString& rkName)
{
ASSERT(pEntry != nullptr);
TWideString SanitizedName = FileUtil::SanitizeName(rkName, false);
TWideString SanitizedDir = FileUtil::SanitizePath(rkDir, true);
if (SanitizedName.IsEmpty()) return;
// trying to keep these as consistent with Retro's naming scheme as possible, and
// for some reason in MP3 they started using all lowercase folder names...
if (pEntry->Game() >= eCorruptionProto)
SanitizedDir = SanitizedDir.ToLower();
CVirtualDirectory *pNewDir = pEntry->ResourceStore()->GetVirtualDirectory(SanitizedDir, false, true);
if (pEntry->Directory() == pNewDir && pEntry->Name() == SanitizedName) return;
@@ -39,89 +47,8 @@ void ApplyGeneratedName(CResourceEntry *pEntry, const TWideString& rkDir, const
ASSERT(Success);
}
TWideString MakeWorldName(EGame Game, TWideString RawName)
{
// The raw world names are basically formatted differently in every single game...
// MP1 demo - Remove ! from the beginning
if (Game == ePrimeDemo)
{
if (RawName.StartsWith(L'!'))
RawName = RawName.ChopFront(1);
}
// MP1 - Remove prefix characters and ending date
else if (Game == ePrime)
{
RawName = RawName.ChopFront(2);
bool StartedDate = false;
while (!RawName.IsEmpty())
{
wchar_t Chr = RawName.Back();
if (!StartedDate && Chr >= L'0' && Chr <= L'9')
StartedDate = true;
else if (StartedDate && Chr != L'_' && (Chr < L'0' || Chr > L'9'))
break;
RawName = RawName.ChopBack(1);
}
}
// MP2 demo - Use text between the first and second underscores
else if (Game == eEchoesDemo)
{
u32 UnderscoreA = RawName.IndexOf(L'_');
u32 UnderscoreB = RawName.IndexOf(L'_', UnderscoreA + 1);
RawName = RawName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
}
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
else if (Game == eEchoes)
{
u32 FirstUnderscore = RawName.IndexOf(L'_');
u32 LastUnderscore = RawName.LastIndexOf(L"_");
if (FirstUnderscore != LastUnderscore)
{
RawName = RawName.ChopBack(RawName.Size() - LastUnderscore);
RawName = RawName.ChopFront(FirstUnderscore + 1);
RawName.Remove(L'_');
}
}
// MP3 proto - Remove ! from the beginning and all text after last underscore
else if (Game == eCorruptionProto)
{
if (RawName.StartsWith(L'!'))
RawName = RawName.ChopFront(1);
u32 LastUnderscore = RawName.LastIndexOf(L"_");
RawName = RawName.ChopBack(RawName.Size() - LastUnderscore);
}
// MP3 - Remove text after last underscore
else if (Game == eCorruption)
{
u32 LastUnderscore = RawName.LastIndexOf(L"_");
RawName = RawName.ChopBack(RawName.Size() - LastUnderscore);
}
// DKCR - Remove text after second-to-last underscore
else if (Game == eReturns)
{
u32 Underscore = RawName.LastIndexOf(L"_");
RawName = RawName.ChopBack(RawName.Size() - Underscore);
Underscore = RawName.LastIndexOf(L"_");
RawName = RawName.ChopBack(RawName.Size() - Underscore);
}
return RawName;
}
void GenerateAssetNames(CGameProject *pProj)
{
// todo: CAUD/CSMP
CResourceStore *pStore = pProj->ResourceStore();
#if PROCESS_PACKAGES
@@ -135,8 +62,11 @@ void GenerateAssetNames(CGameProject *pProj)
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
if (rkRes.Name.EndsWith("NODEPEND")) continue;
// Some of Retro's paks reference assets that don't exist, so we need this check here.
CResourceEntry *pRes = pStore->FindEntry(rkRes.ID);
ApplyGeneratedName(pRes, pPkg->Name().ToUTF16(), rkRes.Name.ToUTF16());
if (pRes)
ApplyGeneratedName(pRes, pPkg->Name().ToUTF16(), rkRes.Name.ToUTF16());
}
}
#endif
@@ -147,8 +77,9 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<eWorld> It(pStore); It; ++It)
{
// Generate world name
TWideString WorldName = MakeWorldName(pProj->Game(), It->Name());
// Set world name
CWorld *pWorld = (CWorld*) It->Load();
TWideString WorldName = L'!' + pWorld->Name().ToUTF16() + L"_Master";
TWideString WorldDir = kWorldsRoot + WorldName + L'\\';
TWideString WorldMasterName = L"!" + WorldName + L"_Master";
@@ -159,10 +90,9 @@ void GenerateAssetNames(CGameProject *pProj)
const TWideString WorldNamesDir = L"Strings\\Worlds\\General\\";
const TWideString AreaNamesDir = TWideString::Format(L"Strings\\Worlds\\%s\\", *WorldName);
CWorld *pWorld = (CWorld*) It->Load();
CModel *pSkyModel = pWorld->DefaultSkybox();
CStringTable *pWorldNameTable = pWorld->WorldName();
CStringTable *pDarkWorldNameTable = pWorld->DarkWorldName();
CStringTable *pWorldNameTable = pWorld->NameString();
CStringTable *pDarkWorldNameTable = pWorld->DarkNameString();
CResource *pSaveWorld = pWorld->SaveWorld();
CResource *pMapWorld = pWorld->MapWorld();
@@ -418,11 +348,34 @@ void GenerateAssetNames(CGameProject *pProj)
#if PROCESS_AUDIO_GROUPS
// Generate Audio Group names
const TWideString kAudioGrpDir = L"Audio\\";
for (TResourceIterator<eAudioGroup> It(pStore); It; ++It)
{
CAudioGroup *pGroup = (CAudioGroup*) It->Load();
TWideString GroupName = pGroup->GroupName().ToUTF16();
ApplyGeneratedName(*It, L"Audio\\", GroupName);
ApplyGeneratedName(*It, kAudioGrpDir, GroupName);
}
#endif
#if PROCESS_AUDIO_MACROS
// Process audio macro/sample names
const TWideString kSfxDir = L"Audio\\Uncategorized\\";
for (TResourceIterator<eAudioMacro> It(pStore); It; ++It)
{
CAudioMacro *pMacro = (CAudioMacro*) It->Load();
TWideString MacroName = pMacro->MacroName().ToUTF16();
ApplyGeneratedName(*It, kSfxDir, MacroName);
for (u32 iSamp = 0; iSamp < pMacro->NumSamples(); iSamp++)
{
CAssetID SampleID = pMacro->SampleByIndex(iSamp);
CResourceEntry *pSample = pStore->FindEntry(SampleID);
if (pSample && !pSample->IsNamed())
ApplyGeneratedName(pSample, kSfxDir, TWideString::Format(L"%s_sample%d", *MacroName, iSamp));
}
}
#endif
@@ -487,6 +440,8 @@ void GenerateAssetNames(CGameProject *pProj)
#if PROCESS_STRINGS
// Generate string names
const TWideString kStringsDir = L"Strings\\Uncategorized\\";
for (TResourceIterator<eStringTable> It(pStore); It; ++It)
{
if (It->IsNamed()) continue;
@@ -504,7 +459,7 @@ void GenerateAssetNames(CGameProject *pProj)
while (Name.EndsWith(L".") || TWideString::IsWhitespace(Name.Back()))
Name = Name.ChopBack(1);
ApplyGeneratedName(pString->Entry(), pString->Entry()->DirectoryPath(), Name);
ApplyGeneratedName(pString->Entry(), kStringsDir, Name);
}
}
#endif

View File

@@ -32,8 +32,7 @@ EDependencyNodeType CDependencyTree::Type() const
void CDependencyTree::Serialize(IArchive& rArc)
{
rArc << SERIAL("RootID", mRootID)
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
rArc << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
}
void CDependencyTree::AddChild(IDependencyNode *pNode)

View File

@@ -47,12 +47,8 @@ public:
// Basic dependency tree; this class is sufficient for most resource types.
class CDependencyTree : public IDependencyNode
{
protected:
CAssetID mRootID;
public:
CDependencyTree() {}
CDependencyTree(const CAssetID& rkID) : mRootID(rkID) {}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
@@ -61,10 +57,6 @@ public:
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
void AddCharacterDependency(const CAnimationParameters& rkAnimParams);
// Accessors
inline void SetID(const CAssetID& rkID) { mRootID = rkID; }
inline CAssetID ID() const { return mRootID; }
};
// Node representing a single resource dependency.
@@ -217,7 +209,6 @@ protected:
public:
CAreaDependencyTree() : CDependencyTree() {}
CAreaDependencyTree(const CAssetID& rkID) : CDependencyTree(rkID) {}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);

View File

@@ -482,11 +482,13 @@ void CGameExporter::ExportResourceEditorData()
{
if (!It->IsTransient())
{
// Worlds need to know which areas can have duplicates. We only have this info at export time.
// Worlds need some info we can only get from the pak at export time; namely, which areas can
// have duplicates, as well as the world's internal name.
if (It->ResourceType() == eWorld)
{
CWorld *pWorld = (CWorld*) It->Load();
// Set area duplicate flags
for (u32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
{
CAssetID AreaID = pWorld->AreaResourceID(iArea);
@@ -495,6 +497,10 @@ void CGameExporter::ExportResourceEditorData()
if (Find != mAreaDuplicateMap.end())
pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second);
}
// Set world name
TString WorldName = MakeWorldName(pWorld->ID());
pWorld->SetName(WorldName);
}
// Save raw resource + generate dependencies
@@ -546,3 +552,115 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
rRes.Exported = true;
}
}
TString CGameExporter::MakeWorldName(CAssetID WorldID)
{
CResourceEntry *pWorldEntry = mpStore->FindEntry(WorldID);
ASSERT(pWorldEntry && pWorldEntry->ResourceType() == eWorld);
// Find the original world name in the package resource names
TString WorldName;
for (u32 iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++)
{
CPackage *pPkg = mpProject->PackageByIndex(iPkg);
for (u32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
if (rkRes.ID == WorldID && !rkRes.Name.EndsWith("_NODEPEND"))
{
WorldName = rkRes.Name;
break;
}
}
if (!WorldName.IsEmpty()) break;
}
// Fix up the name; remove date/time, leading exclamation points, etc
if (!WorldName.IsEmpty())
{
// World names are basically formatted differently in every game...
// MP1 demo - Remove ! from the beginning
if (mGame == ePrimeDemo)
{
if (WorldName.StartsWith('!'))
WorldName = WorldName.ChopFront(1);
}
// MP1 - Remove prefix characters and ending date
else if (mGame == ePrime)
{
WorldName = WorldName.ChopFront(2);
bool StartedDate = false;
while (!WorldName.IsEmpty())
{
char Chr = WorldName.Back();
if (!StartedDate && Chr >= '0' && Chr <= '9')
StartedDate = true;
else if (StartedDate && Chr != '_' && (Chr < '0' || Chr > '9'))
break;
WorldName = WorldName.ChopBack(1);
}
}
// MP2 demo - Use text between the first and second underscores
else if (mGame == eEchoesDemo)
{
u32 UnderscoreA = WorldName.IndexOf('_');
u32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1);
if (UnderscoreA != UnderscoreB && UnderscoreA != -1 && UnderscoreB != -1)
WorldName = WorldName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
}
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
else if (mGame == eEchoes)
{
u32 FirstUnderscore = WorldName.IndexOf('_');
u32 LastUnderscore = WorldName.LastIndexOf('_');
if (FirstUnderscore != LastUnderscore && FirstUnderscore != -1 && LastUnderscore != -1)
{
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
WorldName = WorldName.ChopFront(FirstUnderscore + 1);
WorldName.Remove('_');
}
}
// MP3 proto - Remove ! from the beginning and all text after last underscore
else if (mGame == eCorruptionProto)
{
if (WorldName.StartsWith('!'))
WorldName = WorldName.ChopFront(1);
u32 LastUnderscore = WorldName.LastIndexOf('_');
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
}
// MP3 - Remove text after last underscore
else if (mGame == eCorruption)
{
u32 LastUnderscore = WorldName.LastIndexOf('_');
if (LastUnderscore != -1)
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
}
// DKCR - Remove text after second-to-last underscore
else if (mGame == eReturns)
{
u32 Underscore = WorldName.LastIndexOf('_');
WorldName = WorldName.ChopBack(WorldName.Size() - Underscore);
Underscore = WorldName.LastIndexOf('_');
WorldName = WorldName.ChopBack(WorldName.Size() - Underscore);
}
}
return WorldName;
}

View File

@@ -72,6 +72,7 @@ protected:
void ExportCookedResources();
void ExportResourceEditorData();
void ExportResource(SResourceInstance& rRes);
TString MakeWorldName(CAssetID WorldID);
// Convenience Functions
inline SResourceInstance* FindResourceInstance(const CAssetID& rkID)

View File

@@ -61,7 +61,7 @@ void CResourceEntry::UpdateDependencies()
if (!mpTypeInfo->CanHaveDependencies())
{
mpDependencies = new CDependencyTree(ID());
mpDependencies = new CDependencyTree();
return;
}
@@ -73,7 +73,7 @@ void CResourceEntry::UpdateDependencies()
if (!mpResource)
{
Log::Error("Unable to update cached dependencies; failed to load resource");
mpDependencies = new CDependencyTree(ID());
mpDependencies = new CDependencyTree();
return;
}