Added support for saving/loading package definitions
This commit is contained in:
parent
24c5ad5cd7
commit
f55b3666a0
|
@ -285,4 +285,5 @@ SOURCES += \
|
|||
GameProject/CGameExporter.cpp \
|
||||
GameProject/CResourceStore.cpp \
|
||||
GameProject/CVirtualDirectory.cpp \
|
||||
GameProject/CResourceEntry.cpp
|
||||
GameProject/CResourceEntry.cpp \
|
||||
GameProject/CPackage.cpp
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
#define COPY_DISC_DATA 0
|
||||
#define LOAD_PAKS 1
|
||||
#define EXPORT_WORLDS 1
|
||||
#define EXPORT_COOKED 1
|
||||
#define SAVE_PACKAGE_DEFINITIONS 1
|
||||
#define EXPORT_WORLDS 0
|
||||
#define EXPORT_COOKED 0
|
||||
|
||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||
: mStore(this)
|
||||
|
@ -186,7 +187,8 @@ void CGameExporter::LoadPaks()
|
|||
continue;
|
||||
}
|
||||
|
||||
CPackage *pPackage = new CPackage(CharPak.GetFileName(false), FileUtil::MakeRelative(PakPath.GetFileDirectory(), mGameDir));
|
||||
CPackage *pPackage = new CPackage(mpProject, CharPak.GetFileName(false), FileUtil::MakeRelative(PakPath.GetFileDirectory(), mGameDir));
|
||||
CResourceCollection *pCollection = pPackage->AddCollection("Default");
|
||||
|
||||
// MP1-MP3Proto
|
||||
if (Game() < eCorruption)
|
||||
|
@ -207,7 +209,7 @@ void CGameExporter::LoadPaks()
|
|||
CUniqueID ResID(Pak, IDLength);
|
||||
u32 NameLen = Pak.ReadLong();
|
||||
TString Name = Pak.ReadString(NameLen);
|
||||
pPackage->AddNamedResource(Name, ResID, ResType);
|
||||
pCollection->AddResource(Name, ResID, ResType);
|
||||
}
|
||||
|
||||
u32 NumResources = Pak.ReadLong();
|
||||
|
@ -265,7 +267,7 @@ void CGameExporter::LoadPaks()
|
|||
TString Name = Pak.ReadString();
|
||||
CFourCC ResType = Pak.ReadLong();
|
||||
CUniqueID ResID(Pak, IDLength);
|
||||
pPackage->AddNamedResource(Name, ResID, ResType);
|
||||
pCollection->AddResource(Name, ResID, ResType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,8 +295,11 @@ void CGameExporter::LoadPaks()
|
|||
}
|
||||
}
|
||||
|
||||
// Add package to project
|
||||
// Add package to project and save
|
||||
mpProject->AddPackage(pPackage, IsWorldPak);
|
||||
#if SAVE_PACKAGE_DEFINITIONS
|
||||
pPackage->Save();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -407,15 +412,18 @@ void CGameExporter::ExportWorlds()
|
|||
|
||||
// Get output path. DKCR paks are stored in a Worlds folder so we should get the path relative to that so we don't have Worlds\Worlds\.
|
||||
// Other games have all paks in the game root dir so we're fine just taking the original root dir-relative directory.
|
||||
TWideString PakPath = pPak->PakPath();
|
||||
TWideString PakPath = pPak->Path();
|
||||
TWideString GameWorldsDir = PakPath.GetParentDirectoryPath(L"Worlds", false);
|
||||
|
||||
if (!GameWorldsDir.IsEmpty())
|
||||
PakPath = FileUtil::MakeRelative(PakPath, GameWorldsDir);
|
||||
|
||||
for (u32 iRes = 0; iRes < pPak->NumNamedResources(); iRes++)
|
||||
// Note since there's no collections in the cooked data we're guaranteed that every pak will have exactly one collection.
|
||||
CResourceCollection *pCollection = pPak->CollectionByIndex(0);
|
||||
|
||||
for (u32 iRes = 0; iRes < pCollection->NumResources(); iRes++)
|
||||
{
|
||||
const SNamedResource& rkRes = pPak->NamedResourceByIndex(iRes);
|
||||
const SNamedResource& rkRes = pCollection->ResourceByIndex(iRes);
|
||||
|
||||
if (rkRes.Type == "MLVL" && !rkRes.Name.EndsWith("NODEPEND"))
|
||||
{
|
||||
|
@ -424,7 +432,7 @@ void CGameExporter::ExportWorlds()
|
|||
|
||||
if (!pWorld)
|
||||
{
|
||||
Log::Error("Couldn't load world " + rkRes.Name + " from package " + pPak->PakName() + "; unable to export");
|
||||
Log::Error("Couldn't load world " + rkRes.Name + " from package " + pPak->Name() + "; unable to export");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
inline TWideString DiscDir(bool Relative) const { return Relative ? L"Disc\\" : mProjectRoot + L"Disc\\"; }
|
||||
inline TWideString ContentDir(bool Relative) const { return Relative ? L"Content\\" : mProjectRoot + L"Content\\"; }
|
||||
inline TWideString CookedDir(bool Relative) const { return Relative ? L"Cooked\\" : mProjectRoot + L"Cooked\\"; }
|
||||
inline TWideString PackagesDir(bool Relative) const { return Relative ? L"Packages\\" : mProjectRoot + L"Packages\\"; }
|
||||
|
||||
// Accessors
|
||||
inline void SetGame(EGame Game) { mGame = Game; }
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
#include "CPackage.h"
|
||||
#include "CGameProject.h"
|
||||
#include <Common/AssertMacro.h>
|
||||
#include <Common/FileUtil.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
using namespace tinyxml2;
|
||||
|
||||
void CPackage::Load()
|
||||
{
|
||||
TWideString DefPath = DefinitionPath(false);
|
||||
|
||||
XMLDocument Doc;
|
||||
Doc.LoadFile(*DefPath.ToUTF8());
|
||||
|
||||
if (Doc.Error())
|
||||
{
|
||||
Log::Error("Couldn't open pak definition at path: " + DefPath.ToUTF8());
|
||||
return;
|
||||
}
|
||||
|
||||
XMLElement *pRoot = Doc.FirstChildElement("PackageDefinition");
|
||||
//EPackageDefinitionVersion Version = (EPackageDefinitionVersion) TString(pRoot->Attribute("Version")).ToInt32(10);
|
||||
|
||||
XMLElement *pColElem = pRoot->FirstChildElement("ResourceCollection");
|
||||
|
||||
while (pColElem)
|
||||
{
|
||||
CResourceCollection *pCollection = AddCollection( pColElem->Attribute("Name") );
|
||||
XMLElement *pResElem = pColElem->FirstChildElement("NamedResource");
|
||||
|
||||
while (pResElem)
|
||||
{
|
||||
XMLElement *pNameElem = pResElem->FirstChildElement("Name");
|
||||
XMLElement *pIDElem = pResElem->FirstChildElement("ID");
|
||||
XMLElement *pTypeElem = pResElem->FirstChildElement("Type");
|
||||
|
||||
if (!pIDElem || !pNameElem || !pTypeElem)
|
||||
{
|
||||
TString ElemName = (pNameElem ? (pIDElem ? "Type" : "ID") : "Name");
|
||||
Log::Error("Can't add named resource from pak definition at " + DefPath.ToUTF8() + "; " + ElemName + " element missing");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
CUniqueID ID = CUniqueID::FromString(pIDElem->GetText());
|
||||
TString Name = pNameElem->GetText();
|
||||
CFourCC Type = CFourCC(pTypeElem->GetText());
|
||||
pCollection->AddResource(Name, ID, Type);
|
||||
}
|
||||
|
||||
pResElem = pResElem->NextSiblingElement("NamedResource");
|
||||
}
|
||||
|
||||
pColElem = pColElem->NextSiblingElement("ResourceCollection");
|
||||
}
|
||||
}
|
||||
|
||||
void CPackage::Save()
|
||||
{
|
||||
TWideString DefPath = DefinitionPath(false);
|
||||
FileUtil::CreateDirectory(DefPath.GetFileDirectory());
|
||||
|
||||
// Write XML
|
||||
XMLDocument Doc;
|
||||
|
||||
XMLDeclaration *pDecl = Doc.NewDeclaration();
|
||||
Doc.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pRoot = Doc.NewElement("PackageDefinition");
|
||||
pRoot->SetAttribute("Version", eVer_Current);
|
||||
Doc.LinkEndChild(pRoot);
|
||||
|
||||
for (u32 iCol = 0; iCol < mCollections.size(); iCol++)
|
||||
{
|
||||
CResourceCollection *pCollection = mCollections[iCol];
|
||||
|
||||
XMLElement *pColElem = Doc.NewElement("ResourceCollection");
|
||||
pColElem->SetAttribute("Name", *pCollection->Name());
|
||||
pRoot->LinkEndChild(pColElem);
|
||||
|
||||
for (u32 iRes = 0; iRes < pCollection->NumResources(); iRes++)
|
||||
{
|
||||
const SNamedResource& rkRes = pCollection->ResourceByIndex(iRes);
|
||||
|
||||
XMLElement *pResElem = Doc.NewElement("NamedResource");
|
||||
pColElem->LinkEndChild(pResElem);
|
||||
|
||||
XMLElement *pName = Doc.NewElement("Name");
|
||||
pName->SetText(*rkRes.Name);
|
||||
pResElem->LinkEndChild(pName);
|
||||
|
||||
XMLElement *pID = Doc.NewElement("ID");
|
||||
pID->SetText(*rkRes.ID.ToString());
|
||||
pResElem->LinkEndChild(pID);
|
||||
|
||||
XMLElement *pType = Doc.NewElement("Type");
|
||||
pType->SetText(*rkRes.Type.ToString());
|
||||
pResElem->LinkEndChild(pType);
|
||||
}
|
||||
}
|
||||
|
||||
XMLError Error = Doc.SaveFile(*DefPath.ToUTF8());
|
||||
|
||||
if (Error != XML_SUCCESS)
|
||||
Log::Error("Failed to save pak definition at path: " + DefPath.ToUTF8());
|
||||
}
|
||||
|
||||
TWideString CPackage::DefinitionPath(bool Relative) const
|
||||
{
|
||||
return mpProject->PackagesDir(Relative) + mPakPath + mPakName.ToUTF16() + L".pkd";
|
||||
}
|
||||
|
||||
TWideString CPackage::CookedPackagePath(bool Relative) const
|
||||
{
|
||||
return mpProject->DiscDir(Relative) + mPakPath + mPakName.ToUTF16() + L".pak";
|
||||
}
|
||||
|
||||
CResourceCollection* CPackage::AddCollection(const TString& rkName)
|
||||
{
|
||||
CResourceCollection *pCollection = new CResourceCollection(rkName);
|
||||
mCollections.push_back(pCollection);
|
||||
return pCollection;
|
||||
}
|
||||
|
||||
void CPackage::RemoveCollection(CResourceCollection *pCollection)
|
||||
{
|
||||
for (u32 iCol = 0; iCol < mCollections.size(); iCol++)
|
||||
{
|
||||
if (mCollections[iCol] == pCollection)
|
||||
{
|
||||
RemoveCollection(iCol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPackage::RemoveCollection(u32 Index)
|
||||
{
|
||||
ASSERT(Index < mCollections.size());
|
||||
auto Iter = mCollections.begin() + Index;
|
||||
delete *Iter;
|
||||
mCollections.erase(Iter);
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
#include <Common/CUniqueID.h>
|
||||
#include <Common/TString.h>
|
||||
|
||||
class CGameProject;
|
||||
|
||||
struct SNamedResource
|
||||
{
|
||||
TString Name;
|
||||
|
@ -12,29 +14,66 @@ struct SNamedResource
|
|||
CFourCC Type;
|
||||
};
|
||||
|
||||
class CResourceCollection
|
||||
{
|
||||
TString mName;
|
||||
std::vector<SNamedResource> mNamedResources;
|
||||
|
||||
public:
|
||||
CResourceCollection() : mName("UNNAMED") {}
|
||||
CResourceCollection(const TString& rkName) : mName(rkName) {}
|
||||
|
||||
inline TString Name() const { return mName; }
|
||||
inline u32 NumResources() const { return mNamedResources.size(); }
|
||||
inline const SNamedResource& ResourceByIndex(u32 Idx) const { return mNamedResources[Idx]; }
|
||||
|
||||
inline void AddResource(const TString& rkName, const CUniqueID& rkID, const CFourCC& rkType)
|
||||
{
|
||||
mNamedResources.push_back( SNamedResource { rkName, rkID, rkType } );
|
||||
}
|
||||
};
|
||||
|
||||
class CPackage
|
||||
{
|
||||
CGameProject *mpProject;
|
||||
TString mPakName;
|
||||
TWideString mPakPath;
|
||||
std::vector<SNamedResource> mNamedResources;
|
||||
std::vector<CUniqueID> mPakResources;
|
||||
std::vector<CResourceCollection*> mCollections;
|
||||
|
||||
enum EPackageDefinitionVersion
|
||||
{
|
||||
eVer_Initial,
|
||||
|
||||
eVer_Max,
|
||||
eVer_Current = eVer_Max - 1
|
||||
};
|
||||
|
||||
public:
|
||||
CPackage() {}
|
||||
|
||||
CPackage(const TString& rkName, const TWideString& rkPath)
|
||||
: mPakName(rkName)
|
||||
CPackage(CGameProject *pProj, const TString& rkName, const TWideString& rkPath)
|
||||
: mpProject(pProj)
|
||||
, mPakName(rkName)
|
||||
, mPakPath(rkPath)
|
||||
{}
|
||||
|
||||
inline TString PakName() const { return mPakName; }
|
||||
inline TWideString PakPath() const { return mPakPath; }
|
||||
inline u32 NumNamedResources() const { return mNamedResources.size(); }
|
||||
inline const SNamedResource& NamedResourceByIndex(u32 Index) const { return mNamedResources[Index]; }
|
||||
void Load();
|
||||
void Save();
|
||||
|
||||
inline void SetPakName(TString NewName) { mPakName = NewName; }
|
||||
inline void AddNamedResource(TString Name, const CUniqueID& rkID, const CFourCC& rkType) { mNamedResources.push_back( SNamedResource { Name, rkID, rkType } ); }
|
||||
inline void AddPakResource(const CUniqueID& rkID) { mPakResources.push_back(rkID); }
|
||||
TWideString DefinitionPath(bool Relative) const;
|
||||
TWideString CookedPackagePath(bool Relative) const;
|
||||
|
||||
CResourceCollection* AddCollection(const TString& rkName);
|
||||
void RemoveCollection(CResourceCollection *pCollection);
|
||||
void RemoveCollection(u32 Index);
|
||||
|
||||
// Accessors
|
||||
inline TString Name() const { return mPakName; }
|
||||
inline TWideString Path() const { return mPakPath; }
|
||||
inline u32 NumCollections() const { return mCollections.size(); }
|
||||
inline CResourceCollection* CollectionByIndex(u32 Idx) const { return mCollections[Idx]; }
|
||||
|
||||
inline void SetPakName(TString NewName) { mPakName = NewName; }
|
||||
};
|
||||
|
||||
#endif // CPACKAGE
|
||||
|
|
Loading…
Reference in New Issue