mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-06-05 06:03:37 +00:00
Added resource metadata files
This commit is contained in:
parent
5a398423e1
commit
4b73d0abcc
Binary file not shown.
@ -9,7 +9,7 @@ bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
|
||||
|
||||
if (Reader.IsValid())
|
||||
{
|
||||
CAssetID FileIDLength = CAssetID::GameIDLength(Reader.Game());
|
||||
EIDLength FileIDLength = CAssetID::GameIDLength(Reader.Game());
|
||||
|
||||
if (FileIDLength == mIDLength)
|
||||
{
|
||||
|
@ -531,6 +531,10 @@ void CGameExporter::ExportResourceEditorData()
|
||||
It->Save(true);
|
||||
else
|
||||
It->UpdateDependencies();
|
||||
|
||||
// Set flags, save metadata
|
||||
It->SetFlag(eREF_IsRetroResource);
|
||||
It->SaveMetadata(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
|
||||
, mID(rkID)
|
||||
, mpDirectory(nullptr)
|
||||
, mName(rkFilename)
|
||||
, mMetadataDirty(false)
|
||||
, mCachedSize(-1)
|
||||
, mCachedUppercaseName(rkFilename.ToUpper())
|
||||
{
|
||||
@ -35,12 +36,87 @@ CResourceEntry::~CResourceEntry()
|
||||
if (mpDependencies) delete mpDependencies;
|
||||
}
|
||||
|
||||
void CResourceEntry::SerializeCacheData(IArchive& rArc)
|
||||
bool CResourceEntry::LoadMetadata()
|
||||
{
|
||||
ASSERT(!mMetadataDirty);
|
||||
TString Path = MetadataFilePath();
|
||||
|
||||
if (FileUtil::Exists(Path))
|
||||
{
|
||||
// Validate file
|
||||
CFileInStream MetaFile(Path, IOUtil::eBigEndian);
|
||||
u32 Magic = MetaFile.ReadLong();
|
||||
|
||||
if (Magic == FOURCC('META'))
|
||||
{
|
||||
CSerialVersion Version(MetaFile);
|
||||
CBinaryReader Reader(&MetaFile, Version);
|
||||
SerializeMetadata(Reader);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Error(Path + ": Failed to load metadata file, invalid magic: " + CFourCC(Magic).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CResourceEntry::SaveMetadata(bool ForceSave /*= false*/)
|
||||
{
|
||||
if (mMetadataDirty || ForceSave)
|
||||
{
|
||||
TString Path = MetadataFilePath();
|
||||
TString Dir = Path.GetFileDirectory();
|
||||
FileUtil::MakeDirectory(Dir);
|
||||
|
||||
CFileOutStream MetaFile(Path, IOUtil::eBigEndian);
|
||||
|
||||
if (MetaFile.IsValid())
|
||||
{
|
||||
MetaFile.WriteLong(0); // Magic dummy
|
||||
|
||||
CSerialVersion Version(IArchive::skCurrentArchiveVersion, 0, Game());
|
||||
Version.Write(MetaFile);
|
||||
|
||||
// Scope the binary writer to ensure it finishes before we go back to write the magic value
|
||||
{
|
||||
CBinaryWriter Writer(&MetaFile, Version);
|
||||
SerializeMetadata(Writer);
|
||||
}
|
||||
|
||||
MetaFile.GoTo(0);
|
||||
MetaFile.WriteLong(FOURCC('META'));
|
||||
|
||||
mMetadataDirty = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CResourceEntry::SerializeMetadata(IArchive& rArc)
|
||||
{
|
||||
// Serialize ID. If we already have a valid ID then don't allow the file to override it.
|
||||
CAssetID ID = mID;
|
||||
rArc << SERIAL("AssetID", ID);
|
||||
|
||||
if (rArc.IsReader() && !mID.IsValid())
|
||||
mID = ID;
|
||||
|
||||
// Serialize type
|
||||
rArc << SERIAL("Type", mpTypeInfo);
|
||||
|
||||
// Serialize flags
|
||||
u32 Flags = mFlags & eREF_SavedFlags;
|
||||
rArc << SERIAL_AUTO(Flags);
|
||||
if (rArc.IsReader()) mFlags = Flags & eREF_SavedFlags;
|
||||
}
|
||||
|
||||
void CResourceEntry::SerializeCacheData(IArchive& rArc)
|
||||
{
|
||||
// Note: If the dependency tree format is changed this should be adjusted so that
|
||||
// we regenerate the dependencies from scratch instead of reading the tree if the
|
||||
// file version number is too low
|
||||
@ -92,12 +168,12 @@ bool CResourceEntry::HasCookedVersion() const
|
||||
|
||||
TString CResourceEntry::RawAssetPath(bool Relative) const
|
||||
{
|
||||
return CookedAssetPath(Relative) + ".raw";
|
||||
return CookedAssetPath(Relative) + ".rsraw";
|
||||
}
|
||||
|
||||
TString CResourceEntry::RawExtension() const
|
||||
{
|
||||
return CookedExtension().ToString() + ".raw";
|
||||
return CookedExtension().ToString() + ".rsraw";
|
||||
}
|
||||
|
||||
TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||
@ -113,6 +189,11 @@ CFourCC CResourceEntry::CookedExtension() const
|
||||
return mpTypeInfo->CookedExtension(Game());
|
||||
}
|
||||
|
||||
TString CResourceEntry::MetadataFilePath(bool Relative) const
|
||||
{
|
||||
return CookedAssetPath(Relative) + ".rsmeta";
|
||||
}
|
||||
|
||||
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
||||
{
|
||||
CVirtualDirectory *pParentDir = mpDirectory;
|
||||
@ -146,7 +227,7 @@ bool CResourceEntry::NeedsRecook() const
|
||||
// toggled to arbitrarily flag any asset for recook.
|
||||
if (!HasRawVersion()) return false;
|
||||
if (!HasCookedVersion()) return true;
|
||||
if (mFlags.HasFlag(eREF_NeedsRecook)) return true;
|
||||
if (HasFlag(eREF_NeedsRecook)) return true;
|
||||
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
||||
}
|
||||
|
||||
@ -188,7 +269,7 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
mFlags |= eREF_NeedsRecook;
|
||||
SetFlag(eREF_NeedsRecook);
|
||||
}
|
||||
|
||||
// This resource type doesn't have a raw format; save cooked instead
|
||||
@ -203,11 +284,10 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||
}
|
||||
}
|
||||
|
||||
// Resource has been saved; now make sure dependencies, cache data, and packages are all up to date
|
||||
mFlags |= eREF_HasBeenModified;
|
||||
|
||||
// Resource has been saved; now make sure metadata, dependencies, and packages are all up to date
|
||||
SetFlag(eREF_HasBeenModified);
|
||||
SaveMetadata();
|
||||
UpdateDependencies();
|
||||
mpStore->SetCacheDataDirty();
|
||||
|
||||
if (!SkipCacheSave)
|
||||
{
|
||||
@ -250,9 +330,9 @@ bool CResourceEntry::Cook()
|
||||
|
||||
if (Success)
|
||||
{
|
||||
mFlags &= ~eREF_NeedsRecook;
|
||||
mFlags |= eREF_HasBeenModified;
|
||||
mpStore->SetCacheDataDirty();
|
||||
ClearFlag(eREF_NeedsRecook);
|
||||
SetFlag(eREF_HasBeenModified);
|
||||
SaveMetadata();
|
||||
}
|
||||
|
||||
return Success;
|
||||
@ -458,3 +538,21 @@ EGame CResourceEntry::Game() const
|
||||
{
|
||||
return mpStore ? mpStore->Game() : eUnknownGame;
|
||||
}
|
||||
|
||||
void CResourceEntry::SetFlag(EResEntryFlag Flag)
|
||||
{
|
||||
if (!HasFlag(Flag))
|
||||
{
|
||||
mFlags.SetFlag(Flag);
|
||||
mMetadataDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CResourceEntry::ClearFlag(EResEntryFlag Flag)
|
||||
{
|
||||
if (HasFlag(Flag))
|
||||
{
|
||||
mFlags.ClearFlag(Flag);
|
||||
mMetadataDirty = true;
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,14 @@ class CDependencyTree;
|
||||
enum EResEntryFlag
|
||||
{
|
||||
eREF_NeedsRecook = 0x00000001, // Resource has been updated but not recooked
|
||||
// UNUSED = 0x00000002,
|
||||
eREF_IsRetroResource = 0x00000002, // Resource is from the original game, not user-created
|
||||
eREF_Hidden = 0x00000004, // Resource is hidden, doesn't show up in resource browser
|
||||
eREF_HasBeenModified = 0x00000008, // Resource has been modified and resaved by the user
|
||||
eREF_IsUserResource = 0x00000010, // Resource was created by the user (i.e. isn't a Retro Studios asset)
|
||||
eREF_AutoResName = 0x00000010, // Resource name is auto-generated
|
||||
eREF_AutoResDir = 0x00000020, // Resource directory name is auto-generated
|
||||
// Flags that save to the cache file
|
||||
eREF_SavedFlags = eREF_NeedsRecook | eREF_Hidden | eREF_HasBeenModified | eREF_IsUserResource
|
||||
eREF_SavedFlags = eREF_NeedsRecook | eREF_IsRetroResource | eREF_Hidden | eREF_HasBeenModified |
|
||||
eREF_AutoResName | eREF_AutoResDir
|
||||
};
|
||||
DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
||||
|
||||
@ -37,6 +39,7 @@ class CResourceEntry
|
||||
TString mName;
|
||||
FResEntryFlags mFlags;
|
||||
|
||||
mutable bool mMetadataDirty;
|
||||
mutable u64 mCachedSize;
|
||||
mutable TString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering.
|
||||
|
||||
@ -46,6 +49,9 @@ public:
|
||||
EResType Type);
|
||||
~CResourceEntry();
|
||||
|
||||
bool LoadMetadata();
|
||||
bool SaveMetadata(bool ForceSave = false);
|
||||
void SerializeMetadata(IArchive& rArc);
|
||||
void SerializeCacheData(IArchive& rArc);
|
||||
void UpdateDependencies();
|
||||
|
||||
@ -55,6 +61,7 @@ public:
|
||||
TString RawExtension() const;
|
||||
TString CookedAssetPath(bool Relative = false) const;
|
||||
CFourCC CookedExtension() const;
|
||||
TString MetadataFilePath(bool Relative = false) const;
|
||||
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
||||
u64 Size() const;
|
||||
bool NeedsRecook() const;
|
||||
@ -68,9 +75,14 @@ public:
|
||||
CGameProject* Project() const;
|
||||
EGame Game() const;
|
||||
|
||||
void SetFlag(EResEntryFlag Flag);
|
||||
void ClearFlag(EResEntryFlag Flag);
|
||||
|
||||
// Accessors
|
||||
void SetDirty() { mFlags.SetFlag(eREF_NeedsRecook); }
|
||||
void SetHidden(bool Hidden) { Hidden ? mFlags.SetFlag(eREF_Hidden) : mFlags.ClearFlag(eREF_Hidden); }
|
||||
inline void SetDirty() { SetFlag(eREF_NeedsRecook); }
|
||||
inline void SetHidden(bool Hidden) { Hidden ? SetFlag(eREF_Hidden) : ClearFlag(eREF_Hidden); }
|
||||
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
||||
inline bool IsHidden() const { return HasFlag(eREF_Hidden); }
|
||||
|
||||
inline bool IsLoaded() const { return mpResource != nullptr; }
|
||||
inline bool IsCategorized() const { return mpDirectory && mpDirectory->FullPath() != "Uncategorized/"; }
|
||||
@ -85,7 +97,6 @@ public:
|
||||
inline TString Name() const { return mName; }
|
||||
inline const TString& UppercaseName() const { return mCachedUppercaseName; }
|
||||
inline EResType ResourceType() const { return mpTypeInfo->Type(); }
|
||||
inline bool IsHidden() const { return mFlags.HasFlag(eREF_Hidden); }
|
||||
|
||||
protected:
|
||||
CResource* InternalLoad(IInputStream& rInput);
|
||||
|
@ -138,7 +138,7 @@ bool CResourceStore::LoadCacheFile()
|
||||
// Cache header
|
||||
CFourCC Magic(CacheFile);
|
||||
|
||||
if (Magic != "CACH")
|
||||
if (Magic != FOURCC('CACH'))
|
||||
{
|
||||
Log::Error("Invalid resource cache data magic: " + Magic.ToString());
|
||||
return false;
|
||||
@ -183,8 +183,8 @@ bool CResourceStore::SaveCacheFile()
|
||||
}
|
||||
|
||||
// Cache header
|
||||
CFourCC("CACH").Write(CacheFile);
|
||||
CSerialVersion Version(0, 0, mGame);
|
||||
CacheFile.WriteLong(0); // Magic dummy. Magic isn't written until the rest of the file is saved successfully.
|
||||
CSerialVersion Version(IArchive::skCurrentArchiveVersion, 0, mGame);
|
||||
Version.Write(CacheFile);
|
||||
|
||||
u32 ResCountOffset = CacheFile.Tell();
|
||||
@ -216,6 +216,8 @@ bool CResourceStore::SaveCacheFile()
|
||||
|
||||
CacheFile.Seek(ResCountOffset, SEEK_SET);
|
||||
CacheFile.WriteLong(ResCount);
|
||||
CacheFile.Seek(0, SEEK_SET);
|
||||
CacheFile.WriteLong( FOURCC('CACH') );
|
||||
mCacheFileDirty = false;
|
||||
return true;
|
||||
}
|
||||
@ -295,7 +297,7 @@ void CResourceStore::ConditionalDeleteDirectory(CVirtualDirectory *pDir)
|
||||
{
|
||||
if (pDir->IsEmpty())
|
||||
{
|
||||
// If this directory is part of the project, then we should delete the corresponding filesystem directories
|
||||
// If this directory is part of the project, then we should delete the corresponding filesystem directory
|
||||
if (pDir->GetRoot() == mpDatabaseRoot && !pDir->IsRoot())
|
||||
{
|
||||
FileUtil::DeleteDirectory(ResourcesDir() + pDir->FullPath(), true);
|
||||
@ -338,6 +340,7 @@ CResourceEntry* CResourceStore::RegisterResource(const CAssetID& rkID, EResType
|
||||
if (IsValidResourcePath(rkDir, rkName))
|
||||
{
|
||||
pEntry = new CResourceEntry(this, rkID, rkDir, rkName, Type);
|
||||
pEntry->LoadMetadata();
|
||||
mResourceEntries[rkID] = pEntry;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user