Implemented serialization support and initial support for raw resource formats

This commit is contained in:
parax0
2016-08-09 21:58:27 -06:00
parent b582e7208e
commit 0f2c0d5b39
34 changed files with 1171 additions and 149 deletions

View File

@@ -130,7 +130,6 @@ HEADERS += \
Resource/EResType.h \
Resource/ETevEnums.h \
Resource/ETexelFormat.h \
Resource/SDependency.h \
Resource/TResPtr.h \
Scene/CCollisionNode.h \
Scene/CLightNode.h \
@@ -202,7 +201,9 @@ HEADERS += \
GameProject/CDependencyTree.h \
Resource/Factory/CUnsupportedFormatLoader.h \
Resource/ParticleParameters.h \
Resource/Factory/CUnsupportedParticleLoader.h
Resource/Factory/CUnsupportedParticleLoader.h \
Resource/Resources.h \
Resource/Factory/CResourceFactory.h
# Source Files
SOURCES += \

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -26,6 +26,17 @@ EResType CResource::ResTypeForExtension(CFourCC Extension)
}
// ************ GLOBAL ************
bool ResourceSupportsSerialization(EResType Type)
{
switch (Type)
{
case eWorld:
return true;
default:
return false;
}
}
TString GetResourceTypeName(EResType Type)
{
switch (Type)
@@ -52,8 +63,8 @@ TString GetResourceTypeName(EResType Type)
case eDependencyGroup: return "Dependency Group";
case eDynamicCollision: return "Dynamic Collision";
case eFont: return "Font";
case eGuiFrame: return "GUI Frame";
case eGuiKeyFrame: return "GUI Keyframe";
case eGuiFrame: return "Gui Frame";
case eGuiKeyFrame: return "Gui Keyframe";
case eHintSystem: return "Hint System";
case eMapArea: return "Area Map";
case eMapWorld: return "World Map";
@@ -90,7 +101,7 @@ TString GetResourceTypeName(EResType Type)
case eStringTable: return "String Table";
case eTexture: return "Texture";
case eTweak: return "Tweak Data";
case eUnknown_CAAD: return "Unknown (CAAD)";
case eUnknown_CAAD: return "CAAD";
case eUserEvaluatorData: return "User Evaluator Data";
case eVideo: return "Video";
case eWorld: return "World";
@@ -98,8 +109,16 @@ TString GetResourceTypeName(EResType Type)
}
}
TString GetResourceRawExtension(EResType /*Type*/, EGame /*Game*/)
TString GetResourceSerialName(EResType Type)
{
TString Name = GetResourceTypeName(Type);
Name.RemoveWhitespace();
return Name;
}
TString GetResourceRawExtension(EResType Type, EGame /*Game*/)
{
if (Type == eWorld) return "mwld";
return "";
}

View File

@@ -9,6 +9,7 @@
#include <Common/CFourCC.h>
#include <Common/types.h>
#include <Common/TString.h>
#include <Common/Serialization/IArchive.h>
// This macro creates functions that allow us to easily identify this resource type.
// Must be included on every CResource subclass.
@@ -40,7 +41,8 @@ public:
}
virtual ~CResource() {}
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(ID()); }
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(ID()); }
virtual void Serialize(IArchive& /*rArc*/) {}
inline CResourceEntry* Entry() const { return mpEntry; }
inline TString Source() const { return mpEntry ? mpEntry->CookedAssetPath(true).GetFileName() : ""; }
@@ -56,7 +58,9 @@ public:
};
// Global Functions
bool ResourceSupportsSerialization(EResType Type);
TString GetResourceTypeName(EResType Type);
TString GetResourceSerialName(EResType Type);
TString GetResourceRawExtension(EResType Type, EGame Game);
TString GetResourceCookedExtension(EResType Type, EGame Game);

View File

@@ -23,7 +23,7 @@ CDependencyTree* CWorld::BuildDependencyTree() const
for (u32 iArea = 0; iArea < mAreas.size(); iArea++)
{
pTree->AddDependency(mAreas[iArea].FileID);
pTree->AddDependency(mAreas[iArea].AreaResID);
pTree->AddDependency(mAreas[iArea].pAreaName);
}
@@ -59,3 +59,69 @@ void CWorld::SetAreaLayerInfo(CGameArea *pArea)
pLayer->SetActive(rLayerInfo.EnabledByDefault);
}
}
// ************ SERIALIZATION ************
void CWorld::Serialize(IArchive& rArc)
{
rArc << SERIAL("WorldNameSTRG", mpWorldName)
<< SERIAL("DarkWorldNameSTRG", mpDarkWorldName)
<< SERIAL("WorldSaveInfo", mpSaveWorld)
<< SERIAL("DefaultSkyCMDL", mpDefaultSkybox)
<< SERIAL("MapWorld", mpMapWorld)
<< SERIAL("Unknown1", mUnknown1)
<< SERIAL("UnknownAreas", mUnknownAreas)
<< SERIAL("UnknownAGSC", mUnknownAGSC)
<< SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay")
<< SERIAL_CONTAINER("Areas", mAreas, "Area")
<< SERIAL_CONTAINER("AudioGroups", mAudioGrps, "AudioGroup");
}
void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay)
{
rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID)
<< SERIAL_HEX("TargetID", rMemRelay.TargetID)
<< SERIAL("Message", rMemRelay.Message)
<< SERIAL("Unknown", rMemRelay.Unknown);
}
void Serialize(IArchive& rArc, CWorld::SArea& rArea)
{
rArc << SERIAL("Name", rArea.InternalName)
<< SERIAL("NameSTRG", rArea.pAreaName)
<< SERIAL("Transform", rArea.Transform)
<< SERIAL("BoundingBox", rArea.AetherBox)
<< SERIAL("AreaMREA", rArea.AreaResID)
<< SERIAL_HEX("AreaID", rArea.AreaID)
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
<< SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset")
<< SERIAL("CommonDependsStart", rArea.CommonDependenciesStart)
<< SERIAL_CONTAINER("Docks", rArea.Docks, "Dock")
<< SERIAL_CONTAINER("Layers", rArea.Layers, "Layer");
}
void Serialize(IArchive& rArc, CWorld::SArea::SDock& rDock)
{
rArc << SERIAL_CONTAINER("ConnectingDocks", rDock.ConnectingDocks, "ConnectingDock")
<< SERIAL_CONTAINER("DockCoords", rDock.DockCoordinates, "Coord");
}
void Serialize(IArchive& rArc, CWorld::SArea::SDock::SConnectingDock& rDock)
{
rArc << SERIAL("AreaIndex", rDock.AreaIndex)
<< SERIAL("DockIndex", rDock.DockIndex);
}
void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer)
{
rArc << SERIAL("Name", rLayer.LayerName)
<< SERIAL("DefaultEnabled", rLayer.EnabledByDefault)
<< SERIAL("LayerDependsStart", rLayer.LayerDependenciesStart);
}
void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp)
{
rArc << SERIAL("StudioID", rAudioGrp.Unknown)
<< SERIAL("AGSC", rAudioGrp.ResID);
}

View File

@@ -3,7 +3,6 @@
#include "CResource.h"
#include "CStringTable.h"
#include "SDependency.h"
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Model/CModel.h"
#include <Math/CTransform4f.h>
@@ -27,7 +26,7 @@ class CWorld : public CResource
u32 mUnknownAGSC;
struct SAudioGrp
{
u32 ResID;
CAssetID ResID;
u32 Unknown;
};
std::vector<SAudioGrp> mAudioGrps;
@@ -47,11 +46,11 @@ class CWorld : public CResource
TResPtr<CStringTable> pAreaName;
CTransform4f Transform;
CAABox AetherBox;
u64 FileID; // Loading every single area as a CResource would be a very bad idea
CAssetID AreaResID; // Loading every single area as a CResource would be a very bad idea
u64 AreaID;
std::vector<u16> AttachedAreaIDs;
std::vector<SDependency> Dependencies;
std::vector<CAssetID> Dependencies;
std::vector<TString> RelFilenames;
std::vector<u32> RelOffsets;
u32 CommonDependenciesStart;
@@ -64,7 +63,7 @@ class CWorld : public CResource
u32 DockIndex;
};
std::vector<SConnectingDock> ConnectingDocks;
CVector3f DockCoordinates[4];
std::vector<CVector3f> DockCoordinates;
};
std::vector<SDock> Docks;
@@ -79,7 +78,6 @@ class CWorld : public CResource
};
std::vector<SArea> mAreas;
public:
CWorld(CResourceEntry *pEntry = 0);
~CWorld();
@@ -87,6 +85,15 @@ public:
CDependencyTree* BuildDependencyTree() const;
void SetAreaLayerInfo(CGameArea *pArea);
// Serialization
virtual void Serialize(IArchive& rArc);
friend void Serialize(IArchive& rArc, SMemoryRelay& rMemRelay);
friend void Serialize(IArchive& rArc, SArea& rArea);
friend void Serialize(IArchive& rArc, SArea::SDock& rDock);
friend void Serialize(IArchive& rArc, SArea::SDock::SConnectingDock& rDock);
friend void Serialize(IArchive& rArc, SArea::SLayer& rLayer);
friend void Serialize(IArchive& rArc, SAudioGrp& rAudioGrp);
// Accessors
inline EGame Version() const { return mWorldVersion; }
inline CStringTable* WorldName() const { return mpWorldName; }
@@ -96,7 +103,7 @@ public:
inline CResource* MapWorld() const { return mpMapWorld; }
inline u32 NumAreas() const { return mAreas.size(); }
inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].FileID; }
inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID.ToLongLong(); }
inline u32 AreaAttachedCount(u32 AreaIndex) const { return mAreas[AreaIndex].AttachedAreaIDs.size(); }
inline u32 AreaAttachedID(u32 AreaIndex, u32 AttachedIndex) const { return mAreas[AreaIndex].AttachedAreaIDs[AttachedIndex]; }
inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; }

View File

@@ -0,0 +1,103 @@
#ifndef CRESOURCEFACTORY
#define CRESOURCEFACTORY
#include "CAnimationLoader.h"
#include "CAnimSetLoader.h"
#include "CAreaLoader.h"
#include "CCollisionLoader.h"
#include "CDependencyGroupLoader.h"
#include "CFontLoader.h"
#include "CMaterialLoader.h"
#include "CModelLoader.h"
#include "CPoiToWorldLoader.h"
#include "CScanLoader.h"
#include "CScriptLoader.h"
#include "CSkeletonLoader.h"
#include "CSkinLoader.h"
#include "CStringLoader.h"
#include "CTextureDecoder.h"
#include "CUnsupportedFormatLoader.h"
#include "CUnsupportedParticleLoader.h"
#include "CWorldLoader.h"
#include "Core/Resource/Resources.h"
// Static helper class to allow spawning resources based on an EResType
class CResourceFactory
{
CResourceFactory() {}
public:
static CResource* SpawnResource(CResourceEntry *pEntry)
{
switch (pEntry->ResourceType())
{
case eAnimation: return new CAnimation(pEntry);
case eAnimSet: return new CAnimSet(pEntry);
case eArea: return new CGameArea(pEntry);
case eDynamicCollision: return new CCollisionMeshGroup(pEntry);
case eDependencyGroup: return new CDependencyGroup(pEntry);
case eFont: return new CFont(pEntry);
case eModel: return new CModel(pEntry);
case eScan: return new CScan(pEntry);
case eSkeleton: return new CSkeleton(pEntry);
case eSkin: return new CSkin(pEntry);
case eStaticGeometryMap: return new CPoiToWorld(pEntry);
case eStringTable: return new CStringTable(pEntry);
case eTexture: return new CTexture(pEntry);
case eWorld: return new CWorld(pEntry);
default: return nullptr; // should it return a CResource instead?
}
}
static CResource* LoadCookedResource(CResourceEntry *pEntry, IInputStream& rInput)
{
// Warning: It is the caller's responsibility to check if the required resource is already in memory before calling this function.
if (!rInput.IsValid()) return nullptr;
CResource *pRes = nullptr;
switch (pEntry->ResourceType())
{
case eAnimation: pRes = CAnimationLoader::LoadANIM(rInput, pEntry); break;
case eAnimEventData: pRes = CUnsupportedFormatLoader::LoadEVNT(rInput, pEntry); break;
case eAnimSet: pRes = CAnimSetLoader::LoadANCSOrCHAR(rInput, pEntry); break;
case eArea: pRes = CAreaLoader::LoadMREA(rInput, pEntry); break;
case eDependencyGroup: pRes = CDependencyGroupLoader::LoadDGRP(rInput, pEntry); break;
case eDynamicCollision: pRes = CCollisionLoader::LoadDCLN(rInput, pEntry); break;
case eFont: pRes = CFontLoader::LoadFONT(rInput, pEntry); break;
case eGuiFrame: pRes = CUnsupportedFormatLoader::LoadFRME(rInput, pEntry); break;
case eHintSystem: pRes = CUnsupportedFormatLoader::LoadHINT(rInput, pEntry); break;
case eMapWorld: pRes = CUnsupportedFormatLoader::LoadMAPW(rInput, pEntry); break;
case eMapUniverse: pRes = CUnsupportedFormatLoader::LoadMAPU(rInput, pEntry); break;
case eMidi: pRes = CUnsupportedFormatLoader::LoadCSNG(rInput, pEntry); break;
case eModel: pRes = CModelLoader::LoadCMDL(rInput, pEntry); break;
case eRuleSet: pRes = CUnsupportedFormatLoader::LoadRULE(rInput, pEntry); break;
case eScan: pRes = CScanLoader::LoadSCAN(rInput, pEntry); break;
case eSkeleton: pRes = CSkeletonLoader::LoadCINF(rInput, pEntry); break;
case eSkin: pRes = CSkinLoader::LoadCSKR(rInput, pEntry); break;
case eStaticGeometryMap: pRes = CPoiToWorldLoader::LoadEGMC(rInput, pEntry); break;
case eStringTable: pRes = CStringLoader::LoadSTRG(rInput, pEntry); break;
case eTexture: pRes = CTextureDecoder::LoadTXTR(rInput, pEntry); break;
case eWorld: pRes = CWorldLoader::LoadMLVL(rInput, pEntry); break;
case eParticle:
case eParticleElectric:
case eParticleSwoosh:
case eParticleDecal:
case eParticleWeapon:
case eParticleCollisionResponse:
pRes = CUnsupportedParticleLoader::LoadParticle(rInput, pEntry);
break;
default:
pRes = new CResource(pEntry);
break;
}
return pRes;
}
};
#endif // CRESOURCEFACTORY

View File

@@ -67,13 +67,13 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
if (mVersion < eCorruptionProto)
{
pArea->FileID = rMLVL.ReadLong() & 0xFFFFFFFF; // This is the MREA ID; not actually loading it for obvious reasons
pArea->AreaResID = rMLVL.ReadLong() & 0xFFFFFFFF;
pArea->AreaID = rMLVL.ReadLong() & 0xFFFFFFFF;
}
else
{
pArea->FileID = rMLVL.ReadLongLong();
pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong();
}
@@ -86,7 +86,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
if (mVersion < eCorruptionProto)
rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value (always 0)
// Depedencies
// Dependencies
if (mVersion < eCorruptionProto)
{
u32 NumDependencies = rMLVL.ReadLong();
@@ -94,10 +94,8 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
for (u32 iDep = 0; iDep < NumDependencies; iDep++)
{
SDependency Dependency;
Dependency.ResID = rMLVL.ReadLong() & 0xFFFFFFFF;
Dependency.ResType = rMLVL.ReadLong();
pArea->Dependencies.push_back(Dependency);
pArea->Dependencies.push_back( CAssetID(rMLVL, e32Bit) );
rMLVL.Seek(0x4, SEEK_CUR);
}
/**
@@ -137,7 +135,8 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
}
u32 NumCoordinates = rMLVL.ReadLong();
if (NumCoordinates != 4) Log::Error("Dock coordinate count not 4");
ASSERT(NumCoordinates == 4);
pDock->DockCoordinates.resize(NumCoordinates);
for (u32 iCoord = 0; iCoord < NumCoordinates; iCoord++)
pDock->DockCoordinates[iCoord] = CVector3f(rMLVL);
@@ -245,7 +244,7 @@ void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
pArea->pAreaName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), "STRG");
pArea->Transform = CTransform4f(rMLVL);
pArea->AetherBox = CAABox(rMLVL);
pArea->FileID = rMLVL.ReadLongLong();
pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong();
rMLVL.Seek(0x4, SEEK_CUR);

View File

@@ -0,0 +1,21 @@
#ifndef RESOURCES_H
#define RESOURCES_H
#include "CAnimation.h"
#include "CAnimSet.h"
#include "CCollisionMeshGroup.h"
#include "CDependencyGroup.h"
#include "CFont.h"
#include "CPoiToWorld.h"
#include "CResource.h"
#include "CScan.h"
#include "CSkeleton.h"
#include "CSkin.h"
#include "CStringTable.h"
#include "CTexture.h"
#include "CWorld.h"
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Model/CModel.h"
#endif // RESOURCES_H

View File

@@ -1,14 +0,0 @@
#ifndef SDEPENDENCY
#define SDEPENDENCY
#include <Common/CFourCC.h>
#include <Common/types.h>
struct SDependency
{
u64 ResID;
CFourCC ResType;
};
#endif // SDEPENDENCY

View File

@@ -2,6 +2,7 @@
#define TRESPTR_H
#include "CResource.h"
#include "Core/GameProject/CGameProject.h"
template <typename ResType>
class TResPtr
@@ -30,6 +31,21 @@ public:
mpRes->Release();
}
inline void Serialize(IArchive& rArc)
{
bool IsReader = rArc.IsReader();
EGame ActiveGame = gpResourceStore->ActiveProject()->Game();
CAssetID ID = (mpRes && !IsReader ? mpRes->ID() : (ActiveGame <= eEchoes ? CAssetID::skInvalidID32 : CAssetID::skInvalidID64));
rArc.SerializePrimitive(ID);
if (IsReader)
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
*this = (pEntry ? pEntry->Load() : nullptr);
}
}
inline void Delete()
{
// use with caution! this function exists because not all resources are cached currently