mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-08-12 06:59:18 +00:00
205 lines
6.1 KiB
C++
205 lines
6.1 KiB
C++
#include "CAssetNameMap.h"
|
|
|
|
bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
|
|
{
|
|
if (Path.IsEmpty())
|
|
Path = DefaultNameMapPath(mIDLength);
|
|
|
|
CXMLReader Reader(Path);
|
|
|
|
if (Reader.IsValid())
|
|
{
|
|
EIDLength FileIDLength = CAssetID::GameIDLength(Reader.Game());
|
|
|
|
if (FileIDLength == mIDLength)
|
|
{
|
|
Serialize(Reader);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
debugf("Failed to load asset names; expected %s IDs, got %s",
|
|
mIDLength == k32Bit ? "32-bit" : "64-bit",
|
|
FileIDLength == k32Bit ? "32-bit" : "64-bit" );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorf("Failed to load asset names; couldn't open XML.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CAssetNameMap::SaveAssetNames(TString Path /*= ""*/)
|
|
{
|
|
if (Path.IsEmpty())
|
|
Path = DefaultNameMapPath(mIDLength);
|
|
|
|
EGame Game = (mIDLength == k32Bit ? EGame::Prime : EGame::Corruption);
|
|
CXMLWriter Writer(Path, "AssetNameMap", 0, Game);
|
|
Serialize(Writer);
|
|
return Writer.Save();
|
|
}
|
|
|
|
bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName, bool& rOutAutoGenDir, bool& rOutAutoGenName)
|
|
{
|
|
auto It = mMap.find(ID);
|
|
|
|
if (It != mMap.end())
|
|
{
|
|
SAssetNameInfo& rInfo = It->second;
|
|
rOutName = rInfo.Name;
|
|
rOutDirectory = rInfo.Directory;
|
|
rOutAutoGenDir = rInfo.AutoGenDir;
|
|
rOutAutoGenName = rInfo.AutoGenName;
|
|
return true;
|
|
}
|
|
|
|
else
|
|
{
|
|
EGame Game = (ID.Length() == k32Bit ? EGame::Prime : EGame::Corruption);
|
|
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
|
|
rOutName = ID.ToString();
|
|
rOutAutoGenDir = true;
|
|
rOutAutoGenName = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CAssetNameMap::CopyFromStore(CResourceStore *pStore /*= gpResourceStore*/)
|
|
{
|
|
// Do a first pass to remove old paths from used set to prevent false positives from eg. if two resources switch places
|
|
ASSERT( CAssetID::GameIDLength(pStore->Game()) == mIDLength );
|
|
|
|
for (CResourceIterator It(pStore); It; ++It)
|
|
{
|
|
if (It->IsCategorized() || It->IsNamed())
|
|
{
|
|
auto Find = mMap.find(It->ID());
|
|
|
|
if (Find != mMap.end())
|
|
{
|
|
SAssetNameInfo& rInfo = Find->second;
|
|
auto UsedFind = mUsedSet.find(rInfo);
|
|
ASSERT(UsedFind != mUsedSet.end());
|
|
mUsedSet.erase(UsedFind);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do a second pass to add the new paths to the map
|
|
for (CResourceIterator It(pStore); It; ++It)
|
|
{
|
|
if (It->IsCategorized() || It->IsNamed())
|
|
{
|
|
CAssetID ID = It->ID();
|
|
ASSERT(ID.Length() == mIDLength);
|
|
|
|
TString Name = It->Name();
|
|
TString Directory = It->Directory()->FullPath();
|
|
CFourCC Type = It->CookedExtension();
|
|
bool AutoName = It->HasFlag(EResEntryFlag::AutoResName);
|
|
bool AutoDir = It->HasFlag(EResEntryFlag::AutoResDir);
|
|
SAssetNameInfo NameInfo { Name, Directory, Type, AutoName, AutoDir };
|
|
|
|
// Check for conflicts with new name
|
|
if (mUsedSet.find(NameInfo) != mUsedSet.end())
|
|
{
|
|
SAssetNameInfo NewNameInfo = NameInfo;
|
|
int NumConflicted = 0;
|
|
|
|
while (mUsedSet.find(NewNameInfo) != mUsedSet.end())
|
|
{
|
|
NewNameInfo.Name = NameInfo.Name + '_' + TString::FromInt32(NumConflicted, 0, 10);
|
|
NumConflicted++;
|
|
}
|
|
|
|
TString OldPath = NameInfo.FullPath();
|
|
TString NewPath = NewNameInfo.FullPath();
|
|
warnf("Detected name conflict when copying asset name from the resource store; renaming.");
|
|
warnf("\tOld Path: %s", *OldPath);
|
|
warnf("\tNew Path: %s", *NewPath);
|
|
NameInfo.Name = NewNameInfo.Name;
|
|
}
|
|
|
|
// Assign to map
|
|
mMap[ID] = NameInfo;
|
|
mUsedSet.insert(NameInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ************ PRIVATE ************
|
|
void CAssetNameMap::Serialize(IArchive& rArc)
|
|
{
|
|
rArc << SerialParameter("AssetNameMap", mMap);
|
|
|
|
if (rArc.IsReader())
|
|
PostLoadValidate();
|
|
}
|
|
|
|
void CAssetNameMap::PostLoadValidate()
|
|
{
|
|
// Make sure the newly loaded map doesn't contain any errors or name conflicts.
|
|
bool FoundErrors = false;
|
|
mIsValid = false;
|
|
std::set<SAssetNameInfo> Dupes;
|
|
|
|
for (auto Iter = mMap.begin(); Iter != mMap.end(); Iter++)
|
|
{
|
|
const SAssetNameInfo& rkInfo = Iter->second;
|
|
|
|
if (mUsedSet.find(rkInfo) != mUsedSet.end())
|
|
Dupes.insert(rkInfo);
|
|
|
|
else
|
|
{
|
|
mUsedSet.insert(rkInfo);
|
|
|
|
// Verify the name/path is valid
|
|
if (!CResourceStore::IsValidResourcePath(rkInfo.Directory, rkInfo.Name))
|
|
{
|
|
errorf("Invalid resource path in asset name map: %s%s.%s", *rkInfo.Directory, *rkInfo.Name, *rkInfo.Type.ToString());
|
|
Iter = mMap.erase(Iter);
|
|
FoundErrors = true;
|
|
}
|
|
|
|
// Verify correct ID length
|
|
if (Iter->first.Length() != mIDLength)
|
|
{
|
|
errorf("Incorrect asset ID length in asset name map: %s", *Iter->first.ToString());
|
|
Iter = mMap.erase(Iter);
|
|
FoundErrors = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we detected any dupes, then this map can't be used
|
|
if (!Dupes.empty())
|
|
{
|
|
errorf("Asset name map is invalid and cannot be used! Duplicate asset entries detected:");
|
|
|
|
for (auto Iter = Dupes.begin(); Iter != Dupes.end(); Iter++)
|
|
{
|
|
warnf("\t%s", *Iter->FullPath());
|
|
}
|
|
|
|
mMap.clear();
|
|
}
|
|
else
|
|
mIsValid = !FoundErrors;
|
|
}
|
|
|
|
TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength)
|
|
{
|
|
ASSERT(IDLength != kInvalidIDLength);
|
|
TString Suffix = (IDLength == k32Bit ? "32" : "64");
|
|
return gDataDir + gkAssetMapPath + Suffix + "." + gkAssetMapExt;
|
|
}
|
|
|
|
TString CAssetNameMap::DefaultNameMapPath(EGame Game)
|
|
{
|
|
return DefaultNameMapPath( CAssetID::GameIDLength(Game) );
|
|
}
|