mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-17 08:57:09 +00:00
Implemented serialization support and initial support for raw resource formats
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <Common/CompressionUtil.h>
|
||||
#include <Common/CScopedTimer.h>
|
||||
#include <Common/FileUtil.h>
|
||||
#include <Common/Serialization/CXMLWriter.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#define COPY_DISC_DATA 1
|
||||
@@ -15,7 +16,6 @@
|
||||
#define SAVE_PACKAGE_DEFINITIONS 1
|
||||
#define EXPORT_WORLDS 1
|
||||
#define EXPORT_COOKED 1
|
||||
#define EXPORT_CACHE 1
|
||||
|
||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||
: mStore(this)
|
||||
@@ -76,7 +76,7 @@ void CGameExporter::CopyDiscData()
|
||||
TWideString RelPath = FullPath.ChopFront(mGameDir.Size());
|
||||
|
||||
// Exclude PakTool files and folders
|
||||
if (FullPath.GetFileName(false) == L"PakTool" || FullPath.GetFileName() == L"zlib1" || RelPath.Contains(L"-pak"))
|
||||
if (FullPath.GetFileName(false) == L"PakTool" || FullPath.GetFileName(false) == L"zlib1" || RelPath.Contains(L"-pak"))
|
||||
continue;
|
||||
|
||||
// Hack to determine game
|
||||
@@ -495,20 +495,19 @@ void CGameExporter::ExportCookedResources()
|
||||
#endif
|
||||
mpProject->Save();
|
||||
}
|
||||
#if EXPORT_CACHE
|
||||
{
|
||||
SCOPED_TIMER(SaveCacheData);
|
||||
// Save raw versions of resources + resource cache data files
|
||||
// Note this has to be done after all cooked resources are exported
|
||||
// because we have to load the resource to build its dependency tree and
|
||||
// some resources will fail to load if their dependencies don't exist
|
||||
SCOPED_TIMER(SaveRawResources);
|
||||
|
||||
for (CResourceIterator It(&mStore); It; ++It)
|
||||
{
|
||||
if (!It->IsTransient())
|
||||
{
|
||||
It->UpdateDependencies();
|
||||
It->SaveCacheData();
|
||||
}
|
||||
It->Save();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||
@@ -535,18 +534,17 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||
CResourceEntry *pEntry = mStore.RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), OutDir, OutName);
|
||||
|
||||
#if EXPORT_COOKED
|
||||
// Cooked (todo: save raw)
|
||||
TWideString OutPath = pEntry->CookedAssetPath();
|
||||
FileUtil::CreateDirectory(OutPath.GetFileDirectory());
|
||||
CFileOutStream Out(OutPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
|
||||
// Save cooked asset
|
||||
TWideString OutCookedPath = pEntry->CookedAssetPath();
|
||||
FileUtil::CreateDirectory(OutCookedPath.GetFileDirectory());
|
||||
CFileOutStream Out(OutCookedPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
|
||||
|
||||
if (Out.IsValid())
|
||||
Out.WriteBytes(ResourceData.data(), ResourceData.size());
|
||||
|
||||
rRes.Exported = true;
|
||||
ASSERT(pEntry->HasCookedVersion());
|
||||
#else
|
||||
(void) pEntry; // Prevent "unused local variable" compiler warning
|
||||
#endif
|
||||
|
||||
rRes.Exported = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||
mGame = CMasterTemplate::FindGameForName( pGame->GetText() );
|
||||
mResourceDBPath = pResDB->GetText();
|
||||
|
||||
mProjectRoot = rkPath.GetFileDirectory();
|
||||
mProjectRoot.Replace(L"/", L"\\");
|
||||
|
||||
// Load packages
|
||||
XMLElement *pPkgElem = pPackages->FirstChildElement("Package");
|
||||
|
||||
@@ -67,8 +70,6 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||
}
|
||||
|
||||
// All loaded!
|
||||
mProjectRoot = rkPath.GetFileDirectory();
|
||||
mProjectRoot.Replace(L"/", L"\\");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,30 +2,12 @@
|
||||
#include "CGameProject.h"
|
||||
#include "CResourceStore.h"
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/Factory/CResourceFactory.h"
|
||||
#include <FileIO/FileIO.h>
|
||||
#include <Common/FileUtil.h>
|
||||
#include <Common/TString.h>
|
||||
|
||||
// Resource Loaders
|
||||
// todo: come up with a factory setup that doesn't suck
|
||||
#include "Core/Resource/Factory/CAnimationLoader.h"
|
||||
#include "Core/Resource/Factory/CAnimSetLoader.h"
|
||||
#include "Core/Resource/Factory/CAreaLoader.h"
|
||||
#include "Core/Resource/Factory/CCollisionLoader.h"
|
||||
#include "Core/Resource/Factory/CDependencyGroupLoader.h"
|
||||
#include "Core/Resource/Factory/CFontLoader.h"
|
||||
#include "Core/Resource/Factory/CMaterialLoader.h"
|
||||
#include "Core/Resource/Factory/CModelLoader.h"
|
||||
#include "Core/Resource/Factory/CPoiToWorldLoader.h"
|
||||
#include "Core/Resource/Factory/CScanLoader.h"
|
||||
#include "Core/Resource/Factory/CScriptLoader.h"
|
||||
#include "Core/Resource/Factory/CSkeletonLoader.h"
|
||||
#include "Core/Resource/Factory/CSkinLoader.h"
|
||||
#include "Core/Resource/Factory/CStringLoader.h"
|
||||
#include "Core/Resource/Factory/CTextureDecoder.h"
|
||||
#include "Core/Resource/Factory/CUnsupportedFormatLoader.h"
|
||||
#include "Core/Resource/Factory/CUnsupportedParticleLoader.h"
|
||||
#include "Core/Resource/Factory/CWorldLoader.h"
|
||||
#include <Common/Serialization/CXMLReader.h>
|
||||
#include <Common/Serialization/CXMLWriter.h>
|
||||
|
||||
CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
|
||||
const TWideString& rkDir, const TWideString& rkFilename,
|
||||
@@ -137,6 +119,8 @@ void CResourceEntry::UpdateDependencies()
|
||||
mpDependencies = nullptr;
|
||||
}
|
||||
|
||||
bool WasLoaded = IsLoaded();
|
||||
|
||||
if (!mpResource)
|
||||
Load();
|
||||
|
||||
@@ -147,7 +131,8 @@ void CResourceEntry::UpdateDependencies()
|
||||
}
|
||||
|
||||
mpDependencies = mpResource->BuildDependencyTree();
|
||||
gpResourceStore->DestroyUnreferencedResources();
|
||||
if (!WasLoaded)
|
||||
gpResourceStore->DestroyUnreferencedResources();
|
||||
}
|
||||
|
||||
TWideString CResourceEntry::CacheDataPath(bool Relative) const
|
||||
@@ -229,69 +214,87 @@ void CResourceEntry::SetGame(EGame NewGame)
|
||||
}
|
||||
}
|
||||
|
||||
bool CResourceEntry::Save()
|
||||
{
|
||||
// For now, always save the resource when this function is called even if there's been no changes made to it in memory.
|
||||
// In the future this might not be desired behavior 100% of the time.
|
||||
// We also might want this function to trigger a cook for certain resource types eventually.
|
||||
bool ShouldCollectGarbage = false;
|
||||
|
||||
// Save raw resource
|
||||
if (ResourceSupportsSerialization(ResourceType()))
|
||||
{
|
||||
ShouldCollectGarbage = !IsLoaded();
|
||||
|
||||
Load();
|
||||
if (!mpResource) return false;
|
||||
|
||||
// Note: We call Serialize directly for resources to avoid having a redundant resource root node in the output file.
|
||||
TString Path = RawAssetPath();
|
||||
TString Dir = Path.GetFileDirectory();
|
||||
FileUtil::CreateDirectory(Dir.ToUTF16());
|
||||
|
||||
CXMLWriter Writer(GetResourceSerialName(ResourceType()), Path);
|
||||
mpResource->Serialize(Writer);
|
||||
}
|
||||
|
||||
// Resource has been saved, now update cache file
|
||||
UpdateDependencies();
|
||||
SaveCacheData();
|
||||
|
||||
if (ShouldCollectGarbage)
|
||||
gpResourceStore->DestroyUnreferencedResources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CResource* CResourceEntry::Load()
|
||||
{
|
||||
// todo: load raw
|
||||
// Always try to load raw version as the raw version contains extra editor-only data.
|
||||
// If there is no raw version (which will be the case for resource types that don't
|
||||
// support serialization yet) then load the cooked version as a backup.
|
||||
if (mpResource) return mpResource;
|
||||
|
||||
if (!HasCookedVersion())
|
||||
if (HasRawVersion())
|
||||
{
|
||||
mpResource = CResourceFactory::SpawnResource(this);
|
||||
|
||||
if (mpResource)
|
||||
{
|
||||
CXMLReader Reader(RawAssetPath());
|
||||
mpResource->Serialize(Reader);
|
||||
}
|
||||
|
||||
return mpResource;
|
||||
}
|
||||
|
||||
else if (HasCookedVersion())
|
||||
{
|
||||
CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
|
||||
|
||||
if (!File.IsValid())
|
||||
{
|
||||
Log::Error("Failed to open cooked resource: " + CookedAssetPath(true));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return LoadCooked(File);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Log::Error("Couldn't locate resource: " + CookedAssetPath(true));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
|
||||
if (!File.IsValid())
|
||||
{
|
||||
Log::Error("Failed to open cooked resource: " + CookedAssetPath(true));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Load(File);
|
||||
}
|
||||
|
||||
CResource* CResourceEntry::Load(IInputStream& rInput)
|
||||
CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
|
||||
{
|
||||
// Overload to allow for load from an arbitrary input stream.
|
||||
if (mpResource) return mpResource;
|
||||
if (!rInput.IsValid()) return nullptr;
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break;
|
||||
case eAnimEventData: mpResource = CUnsupportedFormatLoader::LoadEVNT(rInput, this); break;
|
||||
case eAnimSet: mpResource = CAnimSetLoader::LoadANCSOrCHAR(rInput, this); break;
|
||||
case eArea: mpResource = CAreaLoader::LoadMREA(rInput, this); break;
|
||||
case eDependencyGroup: mpResource = CDependencyGroupLoader::LoadDGRP(rInput, this); break;
|
||||
case eDynamicCollision: mpResource = CCollisionLoader::LoadDCLN(rInput, this); break;
|
||||
case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break;
|
||||
case eGuiFrame: mpResource = CUnsupportedFormatLoader::LoadFRME(rInput, this); break;
|
||||
case eHintSystem: mpResource = CUnsupportedFormatLoader::LoadHINT(rInput, this); break;
|
||||
case eMapWorld: mpResource = CUnsupportedFormatLoader::LoadMAPW(rInput, this); break;
|
||||
case eMapUniverse: mpResource = CUnsupportedFormatLoader::LoadMAPU(rInput, this); break;
|
||||
case eMidi: mpResource = CUnsupportedFormatLoader::LoadCSNG(rInput, this); break;
|
||||
case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break;
|
||||
case eRuleSet: mpResource = CUnsupportedFormatLoader::LoadRULE(rInput, this); break;
|
||||
case eScan: mpResource = CScanLoader::LoadSCAN(rInput, this); break;
|
||||
case eSkeleton: mpResource = CSkeletonLoader::LoadCINF(rInput, this); break;
|
||||
case eSkin: mpResource = CSkinLoader::LoadCSKR(rInput, this); break;
|
||||
case eStaticGeometryMap: mpResource = CPoiToWorldLoader::LoadEGMC(rInput, this); break;
|
||||
case eStringTable: mpResource = CStringLoader::LoadSTRG(rInput, this); break;
|
||||
case eTexture: mpResource = CTextureDecoder::LoadTXTR(rInput, this); break;
|
||||
case eWorld: mpResource = CWorldLoader::LoadMLVL(rInput, this); break;
|
||||
|
||||
case eParticle:
|
||||
case eParticleElectric:
|
||||
case eParticleSwoosh:
|
||||
case eParticleDecal:
|
||||
case eParticleWeapon:
|
||||
case eParticleCollisionResponse:
|
||||
mpResource = CUnsupportedParticleLoader::LoadParticle(rInput, this);
|
||||
break;
|
||||
|
||||
default: mpResource = new CResource(this); break;
|
||||
}
|
||||
|
||||
mpResource = CResourceFactory::LoadCookedResource(this, rInput);
|
||||
mpStore->TrackLoadedResource(this);
|
||||
return mpResource;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ public:
|
||||
u64 Size() const;
|
||||
bool NeedsRecook() const;
|
||||
void SetGame(EGame NewGame);
|
||||
bool Save();
|
||||
CResource* Load();
|
||||
CResource* Load(IInputStream& rInput);
|
||||
CResource* LoadCooked(IInputStream& rInput);
|
||||
bool Unload();
|
||||
void Move(const TWideString& rkDir, const TWideString& rkName);
|
||||
void AddToProject(const TWideString& rkDir, const TWideString& rkName);
|
||||
|
||||
@@ -263,7 +263,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
|
||||
CMemoryInStream MemStream(DataBuffer.data(), DataBuffer.size(), IOUtil::eBigEndian);
|
||||
EResType Type = CResource::ResTypeForExtension(rkType);
|
||||
CResourceEntry *pEntry = RegisterTransientResource(Type, rkID);
|
||||
CResource *pRes = pEntry->Load(MemStream);
|
||||
CResource *pRes = pEntry->LoadCooked(MemStream);
|
||||
return pRes;
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
|
||||
CResourceEntry *pEntry = FindEntry(rkID);
|
||||
if (pEntry) return pEntry->Load();
|
||||
|
||||
// Check in transient load directory
|
||||
// Check in transient load directory - this only works for cooked
|
||||
EResType Type = CResource::ResTypeForExtension(rkType);
|
||||
|
||||
if (Type != eInvalidResType)
|
||||
@@ -286,7 +286,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
|
||||
|
||||
TString Path = mTransientLoadDir.ToUTF8() + Name + "." + rkType.ToString();
|
||||
CFileInStream File(Path.ToStdString(), IOUtil::eBigEndian);
|
||||
CResource *pRes = pEntry->Load(File);
|
||||
CResource *pRes = pEntry->LoadCooked(File);
|
||||
|
||||
if (!pRes) DeleteResourceEntry(pEntry);
|
||||
return pRes;
|
||||
@@ -302,6 +302,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
|
||||
|
||||
CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||
{
|
||||
// todo - support loading raw resources from arbitrary directory
|
||||
// Construct ID from string, check if resource is loaded already
|
||||
TWideString Dir = FileUtil::MakeAbsolute(TWideString(rkPath.GetFileDirectory()));
|
||||
TString Name = rkPath.GetFileName(false);
|
||||
@@ -335,7 +336,7 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||
mTransientLoadDir = Dir;
|
||||
|
||||
CResourceEntry *pEntry = RegisterTransientResource(Type, ID, Dir, Name);
|
||||
CResource *pRes = pEntry->Load(File);
|
||||
CResource *pRes = pEntry->LoadCooked(File);
|
||||
if (!pRes) DeleteResourceEntry(pEntry);
|
||||
|
||||
mTransientLoadDir = OldTransientDir;
|
||||
@@ -414,8 +415,6 @@ void CResourceStore::DestroyUnreferencedResources()
|
||||
DirIt = mTransientRoots.erase(DirIt);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Write(TString::FromInt32(mLoadedResources.size(), 0, 10) + " resources loaded");
|
||||
}
|
||||
|
||||
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
|
||||
|
||||
Reference in New Issue
Block a user