Initial implementation of resource database (mainly creation and read/write), and added resource registration system with a registrant for every format from every game
This commit is contained in:
parent
5f2064178c
commit
f15aca3f99
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef CSCOPEDTIMER
|
||||||
|
#define CSCOPEDTIMER
|
||||||
|
|
||||||
|
#include "CTimer.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "TString.h"
|
||||||
|
|
||||||
|
// Runs a timer and automatically stops + prints the time to the log when it goes out of scope.
|
||||||
|
class CScopedTimer
|
||||||
|
{
|
||||||
|
CTimer mTimer;
|
||||||
|
TString mTimerName;
|
||||||
|
bool mStopped;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CScopedTimer(const TString& rkTimeoutMessage)
|
||||||
|
: mTimerName(rkTimeoutMessage)
|
||||||
|
, mStopped(false)
|
||||||
|
{
|
||||||
|
mTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
~CScopedTimer()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
if (!mStopped)
|
||||||
|
{
|
||||||
|
Log::Write(mTimerName + " finished in " + TString::FromFloat((float) mTimer.Stop()) + "s");
|
||||||
|
mStopped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SCOPED_TIMER(TimerName) \
|
||||||
|
CScopedTimer TimerName(#TimerName); \
|
||||||
|
(void) TimerName; // This avoids "unused local variable" compiler warnings
|
||||||
|
|
||||||
|
#endif // CSCOPEDTIMER
|
||||||
|
|
|
@ -73,7 +73,8 @@ HEADERS += \
|
||||||
types.h \
|
types.h \
|
||||||
Log.h \
|
Log.h \
|
||||||
FileUtil.h \
|
FileUtil.h \
|
||||||
AssertMacro.h
|
AssertMacro.h \
|
||||||
|
CScopedTimer.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
|
|
@ -75,6 +75,7 @@ bool DeleteFile(const TWideString& rkFilePath)
|
||||||
|
|
||||||
bool DeleteDirectory(const TWideString& rkDirPath)
|
bool DeleteDirectory(const TWideString& rkDirPath)
|
||||||
{
|
{
|
||||||
|
// This is an extremely destructive function, be careful using it!
|
||||||
if (!IsDirectory(rkDirPath)) return false;
|
if (!IsDirectory(rkDirPath)) return false;
|
||||||
|
|
||||||
// Sanity check - don't delete root
|
// Sanity check - don't delete root
|
||||||
|
@ -94,6 +95,7 @@ bool DeleteDirectory(const TWideString& rkDirPath)
|
||||||
|
|
||||||
bool ClearDirectory(const TWideString& rkDirPath)
|
bool ClearDirectory(const TWideString& rkDirPath)
|
||||||
{
|
{
|
||||||
|
// This is an extremely destructive function, be careful using it!
|
||||||
if (!IsDirectory(rkDirPath)) return false;
|
if (!IsDirectory(rkDirPath)) return false;
|
||||||
|
|
||||||
// Sanity check - don't clear root
|
// Sanity check - don't clear root
|
||||||
|
@ -126,9 +128,14 @@ bool ClearDirectory(const TWideString& rkDirPath)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileSize(const TWideString &rkFilePath)
|
u64 FileSize(const TWideString &rkFilePath)
|
||||||
{
|
{
|
||||||
return (int) (Exists(*rkFilePath) ? file_size(*rkFilePath) : -1);
|
return (u64) (Exists(*rkFilePath) ? file_size(*rkFilePath) : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 LastModifiedTime(const TWideString& rkFilePath)
|
||||||
|
{
|
||||||
|
return (u64) last_write_time(*rkFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
TWideString WorkingDirectory()
|
TWideString WorkingDirectory()
|
||||||
|
|
|
@ -17,9 +17,10 @@ bool CopyDirectory(const TWideString& rkOrigPath, const TWideString& rkNewPath);
|
||||||
bool MoveFile(const TWideString& rkOldPath, const TWideString& rkNewPath);
|
bool MoveFile(const TWideString& rkOldPath, const TWideString& rkNewPath);
|
||||||
bool MoveDirectory(const TWideString& rkOldPath, const TWideString& rkNewPath);
|
bool MoveDirectory(const TWideString& rkOldPath, const TWideString& rkNewPath);
|
||||||
bool DeleteFile(const TWideString& rkFilePath);
|
bool DeleteFile(const TWideString& rkFilePath);
|
||||||
bool DeleteDirectory(const TWideString& rkDirPath);
|
bool DeleteDirectory(const TWideString& rkDirPath); // This is an extremely destructive function, be careful using it!
|
||||||
bool ClearDirectory(const TWideString& rkDirPath);
|
bool ClearDirectory(const TWideString& rkDirPath); // This is an extremely destructive function, be careful using it!
|
||||||
int FileSize(const TWideString& rkFilePath);
|
u64 FileSize(const TWideString& rkFilePath);
|
||||||
|
u64 LastModifiedTime(const TWideString& rkFilePath);
|
||||||
TWideString WorkingDirectory();
|
TWideString WorkingDirectory();
|
||||||
TWideString MakeAbsolute(TWideString Path);
|
TWideString MakeAbsolute(TWideString Path);
|
||||||
TWideString MakeRelative(const TWideString& rkPath, const TWideString& rkRelativeTo = WorkingDirectory());
|
TWideString MakeRelative(const TWideString& rkPath, const TWideString& rkRelativeTo = WorkingDirectory());
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <FileIO/FileIO.h>
|
#include <FileIO/FileIO.h>
|
||||||
#include <Common/AssertMacro.h>
|
#include <Common/AssertMacro.h>
|
||||||
#include <Common/CompressionUtil.h>
|
#include <Common/CompressionUtil.h>
|
||||||
|
#include <Common/CScopedTimer.h>
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
|
|
||||||
#define COPY_DISC_DATA 1
|
#define COPY_DISC_DATA 1
|
||||||
|
@ -9,20 +10,24 @@
|
||||||
#define EXPORT_COOKED 1
|
#define EXPORT_COOKED 1
|
||||||
|
|
||||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||||
: mGameDir( FileUtil::MakeAbsolute(rkInputDir) )
|
|
||||||
, mExportDir( FileUtil::MakeAbsolute(rkOutputDir) )
|
|
||||||
, mDiscDir(mExportDir + L"Disc\\")
|
|
||||||
, mCookedResDir(mExportDir + L"Cooked\\Resources\\")
|
|
||||||
, mCookedWorldsDir(mExportDir + L"Cooked\\Worlds\\")
|
|
||||||
, mRawResDir(mExportDir + L"Raw\\Resources\\")
|
|
||||||
, mRawWorldsDir(mExportDir + L"Raw\\Worlds\\")
|
|
||||||
, mpProject(new CGameProject)
|
|
||||||
{
|
{
|
||||||
|
mGameDir = FileUtil::MakeAbsolute(rkInputDir);
|
||||||
|
mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
|
||||||
|
|
||||||
|
mpProject = new CGameProject(mExportDir);
|
||||||
|
mDiscDir = mpProject->DiscDir();
|
||||||
|
mResDir = mpProject->ResourcesDir();
|
||||||
|
mWorldsDir = mpProject->WorldsDir();
|
||||||
|
mCookedDir = mpProject->CookedDir();
|
||||||
|
mCookedResDir = mpProject->CookedResourcesDir();
|
||||||
|
mCookedWorldsDir = mpProject->CookedWorldsDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameExporter::Export()
|
bool CGameExporter::Export()
|
||||||
{
|
{
|
||||||
|
SCOPED_TIMER(ExportGame);
|
||||||
FileUtil::CreateDirectory(mExportDir);
|
FileUtil::CreateDirectory(mExportDir);
|
||||||
|
FileUtil::ClearDirectory(mExportDir);
|
||||||
CopyDiscData();
|
CopyDiscData();
|
||||||
LoadPaks();
|
LoadPaks();
|
||||||
ExportCookedResources();
|
ExportCookedResources();
|
||||||
|
@ -33,6 +38,8 @@ bool CGameExporter::Export()
|
||||||
void CGameExporter::CopyDiscData()
|
void CGameExporter::CopyDiscData()
|
||||||
{
|
{
|
||||||
#if COPY_DISC_DATA
|
#if COPY_DISC_DATA
|
||||||
|
SCOPED_TIMER(CopyDiscData);
|
||||||
|
|
||||||
// Create Disc output folder
|
// Create Disc output folder
|
||||||
FileUtil::CreateDirectory(mDiscDir);
|
FileUtil::CreateDirectory(mDiscDir);
|
||||||
#endif
|
#endif
|
||||||
|
@ -64,7 +71,7 @@ void CGameExporter::CopyDiscData()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect paks
|
// Detect paks
|
||||||
if (FullPath.GetFileExtension() == L"pak")
|
if (FullPath.GetFileExtension().ToLower() == L"pak")
|
||||||
{
|
{
|
||||||
if (FullPath.GetFileName(false).StartsWith(L"Metroid", false) || RelPath.Contains(L"Worlds", false))
|
if (FullPath.GetFileName(false).StartsWith(L"Metroid", false) || RelPath.Contains(L"Worlds", false))
|
||||||
mWorldPaks.push_back(FullPath);
|
mWorldPaks.push_back(FullPath);
|
||||||
|
@ -90,6 +97,8 @@ void CGameExporter::CopyDiscData()
|
||||||
void CGameExporter::LoadPaks()
|
void CGameExporter::LoadPaks()
|
||||||
{
|
{
|
||||||
#if LOAD_PAKS
|
#if LOAD_PAKS
|
||||||
|
SCOPED_TIMER(LoadPaks);
|
||||||
|
|
||||||
for (u32 iList = 0; iList < 2; iList++)
|
for (u32 iList = 0; iList < 2; iList++)
|
||||||
{
|
{
|
||||||
const TWideStringList& rkList = (iList == 0 ? mWorldPaks : mResourcePaks);
|
const TWideStringList& rkList = (iList == 0 ? mWorldPaks : mResourcePaks);
|
||||||
|
@ -117,31 +126,35 @@ void CGameExporter::LoadPaks()
|
||||||
Pak.Seek(0x4, SEEK_CUR);
|
Pak.Seek(0x4, SEEK_CUR);
|
||||||
ASSERT(PakVersion == 0x00030005);
|
ASSERT(PakVersion == 0x00030005);
|
||||||
|
|
||||||
u32 NumNamedResources = Pak.ReadLong();
|
// Echoes demo disc has a pak that ends right here.
|
||||||
ASSERT(NumNamedResources > 0);
|
if (!Pak.EoF())
|
||||||
|
|
||||||
for (u32 iName = 0; iName < NumNamedResources; iName++)
|
|
||||||
{
|
{
|
||||||
Pak.Seek(0x4, SEEK_CUR); // Skip resource type
|
u32 NumNamedResources = Pak.ReadLong();
|
||||||
CUniqueID ResID(Pak, IDLength);
|
ASSERT(NumNamedResources > 0);
|
||||||
u32 NameLen = Pak.ReadLong();
|
|
||||||
TString Name = Pak.ReadString(NameLen);
|
|
||||||
pPackage->AddNamedResource(Name, ResID);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 NumResources = Pak.ReadLong();
|
for (u32 iName = 0; iName < NumNamedResources; iName++)
|
||||||
|
{
|
||||||
|
Pak.Seek(0x4, SEEK_CUR); // Skip resource type
|
||||||
|
CUniqueID ResID(Pak, IDLength);
|
||||||
|
u32 NameLen = Pak.ReadLong();
|
||||||
|
TString Name = Pak.ReadString(NameLen);
|
||||||
|
pPackage->AddNamedResource(Name, ResID);
|
||||||
|
}
|
||||||
|
|
||||||
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
u32 NumResources = Pak.ReadLong();
|
||||||
{
|
|
||||||
bool Compressed = (Pak.ReadLong() == 1);
|
|
||||||
CFourCC ResType = Pak.ReadLong();
|
|
||||||
CUniqueID ResID(Pak, IDLength);
|
|
||||||
u32 ResSize = Pak.ReadLong();
|
|
||||||
u32 ResOffset = Pak.ReadLong();
|
|
||||||
|
|
||||||
u64 IntegralID = ResID.ToLongLong();
|
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
if (mResourceMap.find(IntegralID) == mResourceMap.end())
|
{
|
||||||
mResourceMap[IntegralID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed };
|
bool Compressed = (Pak.ReadLong() == 1);
|
||||||
|
CFourCC ResType = Pak.ReadLong();
|
||||||
|
CUniqueID ResID(Pak, IDLength);
|
||||||
|
u32 ResSize = Pak.ReadLong();
|
||||||
|
u32 ResOffset = Pak.ReadLong();
|
||||||
|
|
||||||
|
u64 IntegralID = ResID.ToLongLong();
|
||||||
|
if (mResourceMap.find(IntegralID) == mResourceMap.end())
|
||||||
|
mResourceMap[IntegralID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,20 +330,32 @@ void CGameExporter::LoadPakResource(const SResourceInstance& rkResource, std::ve
|
||||||
void CGameExporter::ExportCookedResources()
|
void CGameExporter::ExportCookedResources()
|
||||||
{
|
{
|
||||||
#if EXPORT_COOKED
|
#if EXPORT_COOKED
|
||||||
FileUtil::CreateDirectory(mCookedResDir);
|
CResourceDatabase *pResDB = mpProject->ResourceDatabase();
|
||||||
|
|
||||||
for (auto It = mResourceMap.begin(); It != mResourceMap.end(); It++)
|
|
||||||
{
|
{
|
||||||
const SResourceInstance& rkRes = It->second;
|
SCOPED_TIMER(ExportCookedResources);
|
||||||
std::vector<u8> ResourceData;
|
FileUtil::CreateDirectory(mCookedResDir);
|
||||||
LoadPakResource(rkRes, ResourceData);
|
|
||||||
|
|
||||||
TString OutName = rkRes.ResourceID.ToString() + "." + rkRes.ResourceType.ToString();
|
for (auto It = mResourceMap.begin(); It != mResourceMap.end(); It++)
|
||||||
TString OutPath = mCookedResDir.ToUTF8() + "/" + OutName;
|
{
|
||||||
CFileOutStream Out(OutPath.ToStdString(), IOUtil::eBigEndian);
|
const SResourceInstance& rkRes = It->second;
|
||||||
|
std::vector<u8> ResourceData;
|
||||||
|
LoadPakResource(rkRes, ResourceData);
|
||||||
|
|
||||||
if (Out.IsValid())
|
TString OutName = rkRes.ResourceID.ToString() + "." + rkRes.ResourceType.ToString();
|
||||||
Out.WriteBytes(ResourceData.data(), ResourceData.size());
|
TString OutDir = mCookedResDir.ToUTF8() + "\\";
|
||||||
|
TString OutPath = OutDir + OutName;
|
||||||
|
CFileOutStream Out(OutPath.ToStdString(), IOUtil::eBigEndian);
|
||||||
|
|
||||||
|
if (Out.IsValid())
|
||||||
|
Out.WriteBytes(ResourceData.data(), ResourceData.size());
|
||||||
|
|
||||||
|
// Add to resource DB
|
||||||
|
pResDB->RegisterResource(rkRes.ResourceID, FileUtil::MakeRelative(OutDir, mCookedDir), OutName, CResource::ResTypeForExtension(rkRes.ResourceType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
SCOPED_TIMER(SaveResourceDatabase);
|
||||||
|
pResDB->Save(this->mExportDir.ToUTF8() + "ResourceDatabase.rdb");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,11 @@ class CGameExporter
|
||||||
TWideString mGameDir;
|
TWideString mGameDir;
|
||||||
TWideString mExportDir;
|
TWideString mExportDir;
|
||||||
TWideString mDiscDir;
|
TWideString mDiscDir;
|
||||||
|
TWideString mResDir;
|
||||||
|
TWideString mWorldsDir;
|
||||||
|
TWideString mCookedDir;
|
||||||
TWideString mCookedResDir;
|
TWideString mCookedResDir;
|
||||||
TWideString mCookedWorldsDir;
|
TWideString mCookedWorldsDir;
|
||||||
TWideString mRawResDir;
|
|
||||||
TWideString mRawWorldsDir;
|
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
TWideStringList mWorldPaks;
|
TWideStringList mWorldPaks;
|
||||||
|
|
|
@ -12,20 +12,31 @@ class CGameProject
|
||||||
{
|
{
|
||||||
EGame mGame;
|
EGame mGame;
|
||||||
TString mProjectName;
|
TString mProjectName;
|
||||||
TString mProjectRoot;
|
TWideString mProjectRoot;
|
||||||
CResourceDatabase *mpResourceDatabase;
|
CResourceDatabase *mpResourceDatabase;
|
||||||
std::vector<CPackage*> mWorldPaks;
|
std::vector<CPackage*> mWorldPaks;
|
||||||
std::vector<CPackage*> mResourcePaks;
|
std::vector<CPackage*> mResourcePaks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGameProject()
|
CGameProject(const TWideString& rkProjRootDir)
|
||||||
: mGame(eUnknownVersion)
|
: mGame(eUnknownVersion)
|
||||||
, mProjectName("UnnamedProject")
|
, mProjectName("UnnamedProject")
|
||||||
, mpResourceDatabase(new CResourceDatabase)
|
, mProjectRoot(rkProjRootDir)
|
||||||
|
, mpResourceDatabase(new CResourceDatabase(this))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void AddPackage(CPackage *pPackage, bool WorldPak);
|
void AddPackage(CPackage *pPackage, bool WorldPak);
|
||||||
|
|
||||||
|
// Directory Handling
|
||||||
|
inline TWideString ProjectRoot() const { return mProjectRoot; }
|
||||||
|
inline TWideString DiscDir() const { return mProjectRoot + L"Disc\\"; }
|
||||||
|
inline TWideString ResourcesDir() const { return mProjectRoot + L"Resources\\"; }
|
||||||
|
inline TWideString WorldsDir() const { return mProjectRoot + L"Worlds\\"; }
|
||||||
|
inline TWideString CookedDir() const { return mProjectRoot + L"Cooked\\"; }
|
||||||
|
inline TWideString CookedResourcesDir() const { return CookedDir() + L"Resources\\"; }
|
||||||
|
inline TWideString CookedWorldsDir() const { return CookedDir() + L"Worlds\\"; }
|
||||||
|
|
||||||
|
// Accessors
|
||||||
inline void SetGame(EGame Game) { mGame = Game; }
|
inline void SetGame(EGame Game) { mGame = Game; }
|
||||||
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; }
|
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; }
|
||||||
|
|
||||||
|
|
|
@ -1 +1,215 @@
|
||||||
#include "CResourceDatabase.h"
|
#include "CResourceDatabase.h"
|
||||||
|
#include "CGameProject.h"
|
||||||
|
#include "Core/Resource/CResCache.h"
|
||||||
|
#include <Common/AssertMacro.h>
|
||||||
|
#include <Common/FileUtil.h>
|
||||||
|
#include <Common/Log.h>
|
||||||
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
using namespace tinyxml2;
|
||||||
|
|
||||||
|
// ************ CResourceEntry ************
|
||||||
|
bool CResourceEntry::HasRawVersion() const
|
||||||
|
{
|
||||||
|
return FileUtil::Exists(RawAssetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CResourceEntry::HasCookedVersion() const
|
||||||
|
{
|
||||||
|
return FileUtil::Exists(CookedAssetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
TString CResourceEntry::RawAssetPath() const
|
||||||
|
{
|
||||||
|
TWideString Ext = GetRawExtension(mResourceType, mpDatabase->GameProject()->Game()).ToUTF16();
|
||||||
|
return mpDatabase->GameProject()->ProjectRoot() + mFileDir + mFileName + L"." + Ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
TString CResourceEntry::CookedAssetPath() const
|
||||||
|
{
|
||||||
|
TWideString Ext = GetCookedExtension(mResourceType, mpDatabase->GameProject()->Game()).ToUTF16();
|
||||||
|
return mpDatabase->GameProject()->CookedDir() + mFileDir + mFileName + L"." + Ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CResourceEntry::NeedsRecook() const
|
||||||
|
{
|
||||||
|
// Assets that do not have a raw version can't be recooked since they will always just be saved cooked to begin with.
|
||||||
|
// We will recook any asset where the raw version has been updated but not recooked yet. mNeedsRecook can also be
|
||||||
|
// toggled to arbitrarily flag any asset for recook.
|
||||||
|
if (!HasRawVersion()) return false;
|
||||||
|
if (!HasCookedVersion()) return true;
|
||||||
|
if (mNeedsRecook) return true;
|
||||||
|
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CResourceDatabase ************
|
||||||
|
CResourceDatabase::CResourceDatabase(CGameProject *pProj)
|
||||||
|
: mpProj(pProj)
|
||||||
|
{}
|
||||||
|
|
||||||
|
CResourceDatabase::~CResourceDatabase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceDatabase::Load(const TString& rkPath)
|
||||||
|
{
|
||||||
|
XMLDocument Doc;
|
||||||
|
Doc.LoadFile(*rkPath);
|
||||||
|
|
||||||
|
if (!Doc.Error())
|
||||||
|
{
|
||||||
|
XMLElement *pRoot = Doc.FirstChildElement("ResourceDatabase");
|
||||||
|
//EVersion DatabaseVersion = (EVersion) TString(pRoot->Attribute("Version")).ToInt32(10); // Version currently unused
|
||||||
|
|
||||||
|
XMLElement *pResources = pRoot->FirstChildElement("Resources");
|
||||||
|
XMLElement *pRes = pResources->FirstChildElement("Resource");
|
||||||
|
u32 ResIndex = 0;
|
||||||
|
|
||||||
|
while (pRes)
|
||||||
|
{
|
||||||
|
XMLElement *pChild = pRes->FirstChildElement();
|
||||||
|
|
||||||
|
bool HasID = false, HasType = false, HasDir = false, HasName = false;
|
||||||
|
CUniqueID ID;
|
||||||
|
EResType Type;
|
||||||
|
TWideString FileDir;
|
||||||
|
TWideString FileName;
|
||||||
|
|
||||||
|
while (pChild)
|
||||||
|
{
|
||||||
|
TString NodeName = pChild->Name();
|
||||||
|
|
||||||
|
if (NodeName == "ID")
|
||||||
|
{
|
||||||
|
ID = CUniqueID::FromString(pChild->GetText());
|
||||||
|
HasID = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (NodeName == "Type")
|
||||||
|
{
|
||||||
|
Type = CResource::ResTypeForExtension(pChild->GetText());
|
||||||
|
HasType = true;
|
||||||
|
ASSERT(Type != eInvalidResType);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (NodeName == "FileDir")
|
||||||
|
{
|
||||||
|
FileDir = pChild->GetText();
|
||||||
|
HasDir = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (NodeName == "FileName")
|
||||||
|
{
|
||||||
|
FileName = pChild->GetText();
|
||||||
|
HasName = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pChild = pChild->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasID && HasType && HasDir && HasName)
|
||||||
|
RegisterResource(ID, FileDir, FileName, Type);
|
||||||
|
else
|
||||||
|
Log::Error("Error reading " + rkPath + ": Resource entry " + TString::FromInt32(ResIndex, 0, 10) + " is missing one or more components");
|
||||||
|
|
||||||
|
ResIndex++;
|
||||||
|
pRes = pRes->NextSiblingElement("Resource");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceDatabase::Save(const TString& rkPath) const
|
||||||
|
{
|
||||||
|
XMLDocument Doc;
|
||||||
|
|
||||||
|
XMLDeclaration *pDecl = Doc.NewDeclaration();
|
||||||
|
Doc.LinkEndChild(pDecl);
|
||||||
|
|
||||||
|
XMLElement *pRoot = Doc.NewElement("ResourceDatabase");
|
||||||
|
pRoot->SetAttribute("Version", eVer_Current);
|
||||||
|
Doc.LinkEndChild(pRoot);
|
||||||
|
|
||||||
|
XMLElement *pResources = Doc.NewElement("Resources");
|
||||||
|
pRoot->LinkEndChild(pResources);
|
||||||
|
|
||||||
|
for (auto It = mResourceMap.begin(); It != mResourceMap.end(); It++)
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = It->second;
|
||||||
|
XMLElement *pRes = Doc.NewElement("Resource");
|
||||||
|
pResources->LinkEndChild(pRes);
|
||||||
|
|
||||||
|
XMLElement *pID = Doc.NewElement("ID");
|
||||||
|
pID->SetText(*pEntry->ID().ToString());
|
||||||
|
pRes->LinkEndChild(pID);
|
||||||
|
|
||||||
|
XMLElement *pType = Doc.NewElement("Type");
|
||||||
|
pType->SetText(*GetCookedExtension(pEntry->ResourceType(), mpProj->Game()));
|
||||||
|
pRes->LinkEndChild(pType);
|
||||||
|
|
||||||
|
XMLElement *pDir = Doc.NewElement("FileDir");
|
||||||
|
pDir->SetText(*pEntry->FileDirectory());
|
||||||
|
pRes->LinkEndChild(pDir);
|
||||||
|
|
||||||
|
XMLElement *pName = Doc.NewElement("FileName");
|
||||||
|
pName->SetText(*pEntry->FileName());
|
||||||
|
pRes->LinkEndChild(pName);
|
||||||
|
|
||||||
|
XMLElement *pRecook = Doc.NewElement("NeedsRecook");
|
||||||
|
pRecook->SetText(pEntry->NeedsRecook() ? "true" : "false");
|
||||||
|
pRes->LinkEndChild(pRecook);
|
||||||
|
}
|
||||||
|
|
||||||
|
Doc.SaveFile(*rkPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
CResourceEntry* CResourceDatabase::FindResourceEntry(const CUniqueID& rkID) const
|
||||||
|
{
|
||||||
|
auto Found = mResourceMap.find(rkID);
|
||||||
|
if (Found == mResourceMap.end()) return nullptr;
|
||||||
|
else return Found->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
CResource* CResourceDatabase::LoadResource(const CUniqueID& rkID) const
|
||||||
|
{
|
||||||
|
// todo: no handling for raw assets yet
|
||||||
|
CResourceEntry *pEntry = FindResourceEntry(rkID);
|
||||||
|
|
||||||
|
if (pEntry)
|
||||||
|
{
|
||||||
|
TString AssetPath = pEntry->CookedAssetPath();
|
||||||
|
|
||||||
|
if (FileUtil::Exists(AssetPath))
|
||||||
|
return gResCache.GetResource(pEntry->CookedAssetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CResourceDatabase::RegisterResource(const CUniqueID& rkID, const TWideString& rkDir, const TWideString& rkFileName, EResType Type)
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = FindResourceEntry(rkID);
|
||||||
|
|
||||||
|
if (pEntry)
|
||||||
|
{
|
||||||
|
Log::Error("Attempted to register resource that's already tracked in the database: " + rkID.ToString() + " / " + rkDir.ToUTF8() + " / " + rkFileName.ToUTF8());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry = new CResourceEntry(this, rkID, rkDir, rkFileName.GetFileName(false), Type);
|
||||||
|
|
||||||
|
if (!pEntry->HasCookedVersion() && !pEntry->HasRawVersion())
|
||||||
|
{
|
||||||
|
Log::Error("Attempted to register a resource that doesn't exist: " + rkID.ToString() + " | " + rkDir.ToUTF8() + " | " + rkFileName.ToUTF8());
|
||||||
|
delete pEntry;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mResourceMap[rkID] = pEntry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +1,74 @@
|
||||||
#ifndef CRESOURCEDATABASE_H
|
#ifndef CRESOURCEDATABASE_H
|
||||||
#define CRESOURCEDATABASE_H
|
#define CRESOURCEDATABASE_H
|
||||||
|
|
||||||
|
#include "Core/Resource/CResource.h"
|
||||||
#include <Common/CUniqueID.h>
|
#include <Common/CUniqueID.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class CGameProject;
|
||||||
|
class CResourceDatabase;
|
||||||
|
|
||||||
class CResourceEntry
|
class CResourceEntry
|
||||||
{
|
{
|
||||||
CUniqueID ID;
|
CResourceDatabase *mpDatabase;
|
||||||
TString DataPath;
|
CUniqueID mID;
|
||||||
|
TWideString mFileDir;
|
||||||
|
TWideString mFileName;
|
||||||
|
EResType mResourceType;
|
||||||
|
bool mNeedsRecook;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CResourceEntry(CResourceDatabase *pDatabase, const CUniqueID& rkID,
|
||||||
|
const TWideString& rkDir, const TWideString& rkFilename, EResType Type)
|
||||||
|
: mpDatabase(pDatabase)
|
||||||
|
, mID(rkID)
|
||||||
|
, mFileDir(rkDir)
|
||||||
|
, mFileName(rkFilename)
|
||||||
|
, mResourceType(Type)
|
||||||
|
, mNeedsRecook(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool HasRawVersion() const;
|
||||||
|
bool HasCookedVersion() const;
|
||||||
|
TString RawAssetPath() const;
|
||||||
|
TString CookedAssetPath() const;
|
||||||
|
bool NeedsRecook() const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
void SetDirty() { mNeedsRecook = true; }
|
||||||
|
|
||||||
|
inline CUniqueID ID() const { return mID; }
|
||||||
|
inline TString FileDirectory() const { return mFileDir; }
|
||||||
|
inline TString FileName() const { return mFileName; }
|
||||||
|
inline EResType ResourceType() const { return mResourceType; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CResourceDatabase
|
class CResourceDatabase
|
||||||
{
|
{
|
||||||
struct SResEntry
|
CGameProject *mpProj;
|
||||||
|
std::map<CUniqueID, CResourceEntry*> mResourceMap;
|
||||||
|
|
||||||
|
enum EVersion
|
||||||
{
|
{
|
||||||
CUniqueID ID;
|
eVer_Initial,
|
||||||
TString DataPath;
|
|
||||||
|
eVer_Max,
|
||||||
|
eVer_Current = eVer_Max - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceDatabase() {}
|
CResourceDatabase(CGameProject *pProj);
|
||||||
~CResourceDatabase() {}
|
~CResourceDatabase();
|
||||||
|
void Load(const TString& rkPath);
|
||||||
|
void Save(const TString& rkPath) const;
|
||||||
|
|
||||||
|
CResourceEntry* FindResourceEntry(const CUniqueID& rkID) const;
|
||||||
|
CResource* LoadResource(const CUniqueID& rkID) const;
|
||||||
|
bool RegisterResource(const CUniqueID& rkID, const TWideString& rkDir, const TWideString& rkFileName, EResType Type);
|
||||||
|
|
||||||
|
inline CGameProject* GameProject() const { return mpProj; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CRESOURCEDATABASE_H
|
#endif // CRESOURCEDATABASE_H
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
class CCollisionMeshGroup : public CResource
|
class CCollisionMeshGroup : public CResource
|
||||||
{
|
{
|
||||||
DECLARE_RESOURCE_TYPE(eCollisionMeshGroup)
|
DECLARE_RESOURCE_TYPE(eDynamicCollision)
|
||||||
std::vector<CCollisionMesh*> mMeshes;
|
std::vector<CCollisionMesh*> mMeshes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
class CPoiToWorld : public CResource
|
class CPoiToWorld : public CResource
|
||||||
{
|
{
|
||||||
DECLARE_RESOURCE_TYPE(ePoiToWorld)
|
DECLARE_RESOURCE_TYPE(eStaticGeometryMap)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct SPoiMap
|
struct SPoiMap
|
||||||
|
|
|
@ -1,69 +1,140 @@
|
||||||
#include "CResource.h"
|
#include "CResource.h"
|
||||||
|
#include <Common/AssertMacro.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
std::map<u32, EResType> gExtensionTypeMap;
|
||||||
|
std::map<u32, TString> gTypeExtensionMap;
|
||||||
|
|
||||||
|
u32 GetGameTypeID(EGame Game, EResType ResType)
|
||||||
|
{
|
||||||
|
return ((Game & 0xFFFF) << 16) | (ResType & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
EResType CResource::ResTypeForExtension(CFourCC Extension)
|
EResType CResource::ResTypeForExtension(CFourCC Extension)
|
||||||
{
|
{
|
||||||
Extension = Extension.ToUpper();
|
auto Find = gExtensionTypeMap.find(Extension.ToLong());
|
||||||
|
|
||||||
if (Extension < "FONT")
|
if (Find == gExtensionTypeMap.end())
|
||||||
{
|
{
|
||||||
if (Extension < "CSKR")
|
Log::Error("Couldn't find resource type for requested cooked extension: " + Extension.ToString());
|
||||||
{
|
return eInvalidResType;
|
||||||
if (Extension == "AFSM") return eStateMachine;
|
|
||||||
if (Extension == "AGSC") return eAudioGrp;
|
|
||||||
if (Extension == "ANCS") return eAnimSet;
|
|
||||||
if (Extension == "ANIM") return eAnimation;
|
|
||||||
if (Extension == "ATBL") return eAudioTable;
|
|
||||||
if (Extension == "CAUD") return eAudioData;
|
|
||||||
if (Extension == "CHAR") return eAnimSet;
|
|
||||||
if (Extension == "CINF") return eSkeleton;
|
|
||||||
if (Extension == "CMDL") return eModel;
|
|
||||||
if (Extension == "CRSC") return eCollisionResponse;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Extension == "CSKR") return eSkin;
|
|
||||||
if (Extension == "CSMP") return eAudioSample;
|
|
||||||
if (Extension == "CSNG") return eMidi;
|
|
||||||
if (Extension == "CTWK") return eTweak;
|
|
||||||
if (Extension == "DCLN") return eCollisionMeshGroup;
|
|
||||||
if (Extension == "DGRP") return eDependencyGroup;
|
|
||||||
if (Extension == "DSP ") return eMusicTrack;
|
|
||||||
if (Extension == "DUMB") return eDataDump;
|
|
||||||
if (Extension == "ELSC") return eParticleElectric;
|
|
||||||
if (Extension == "EVNT") return eAnimEventData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Extension < "PAK ")
|
|
||||||
{
|
|
||||||
if (Extension == "FONT") return eFont;
|
|
||||||
if (Extension == "FRME") return eGuiFrame;
|
|
||||||
if (Extension == "FSM2") return eStateMachine;
|
|
||||||
if (Extension == "HINT") return eHintSystem;
|
|
||||||
if (Extension == "MAPA") return eMapArea;
|
|
||||||
if (Extension == "MAPW") return eMapWorld;
|
|
||||||
if (Extension == "MAPU") return eMapUniverse;
|
|
||||||
if (Extension == "MLVL") return eWorld;
|
|
||||||
if (Extension == "MREA") return eArea;
|
|
||||||
if (Extension == "NTWK") return eTweak;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Extension == "PAK ") return ePackFile;
|
|
||||||
if (Extension == "PART") return eParticle;
|
|
||||||
if (Extension == "PATH") return eNavMesh;
|
|
||||||
if (Extension == "SAVW") return eSaveWorld;
|
|
||||||
if (Extension == "SCAN") return eScan;
|
|
||||||
if (Extension == "STRG") return eStringTable;
|
|
||||||
if (Extension == "STRM") return eAudioStream;
|
|
||||||
if (Extension == "SWHC") return eParticleSwoosh;
|
|
||||||
if (Extension == "THP ") return eVideo;
|
|
||||||
if (Extension == "TXTR") return eTexture;
|
|
||||||
if (Extension == "WPSC") return eProjectile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return eInvalidResType;
|
return Find->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementation of functions declared in EResType.h
|
||||||
|
TString GetRawExtension(EResType /*Type*/, EGame /*Game*/)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
TString GetCookedExtension(EResType Type, EGame Game)
|
||||||
|
{
|
||||||
|
u32 GameTypeID = GetGameTypeID(Game, Type);
|
||||||
|
auto Find = gTypeExtensionMap.find(GameTypeID);
|
||||||
|
if (Find != gTypeExtensionMap.end()) return Find->second;
|
||||||
|
else return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ TYPE REGISTRATIONS ************
|
||||||
|
/* This macro registers a resource's cooked extension with an EResType enum, which allows for
|
||||||
|
* a resource type to be looked up via its extension, and vice versa. Because certain EResType
|
||||||
|
* enumerators are reused with different extensions between games, it's possible to set up a
|
||||||
|
* registration to be valid for only a specific range of games, and then tie a different
|
||||||
|
* extension to the same enumerator for a different game. This allows you to always look up the
|
||||||
|
* correct extension for a given resource type with a combination of an EResType and an EGame.
|
||||||
|
*
|
||||||
|
* You shouldn't need to add any new resource types, as the currently registered ones cover every
|
||||||
|
* resource type for every game from the MP1 demo up to DKCR. However, if you do, simply add an
|
||||||
|
* extra REGISTER_RESOURCE_TYPE line to the list below.
|
||||||
|
*/
|
||||||
|
#define REGISTER_RESOURCE_TYPE(CookedExtension, TypeEnum, FirstGame, LastGame) \
|
||||||
|
class CResourceTypeRegistrant__##CookedExtension \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
CResourceTypeRegistrant__##CookedExtension() \
|
||||||
|
{ \
|
||||||
|
ASSERT(FirstGame != eUnknownVersion); \
|
||||||
|
\
|
||||||
|
/* Register extension with resource type (should be consistent across all games) */ \
|
||||||
|
u32 IntExt = CFourCC(#CookedExtension).ToLong(); \
|
||||||
|
auto ExtFind = gExtensionTypeMap.find(IntExt); \
|
||||||
|
if (ExtFind != gExtensionTypeMap.end()) \
|
||||||
|
ASSERT(ExtFind->second == TypeEnum); \
|
||||||
|
\
|
||||||
|
gExtensionTypeMap[IntExt] = TypeEnum; \
|
||||||
|
\
|
||||||
|
/* Register resource type with extension for the specified game range */ \
|
||||||
|
EGame Game = FirstGame; \
|
||||||
|
\
|
||||||
|
while (Game <= LastGame) \
|
||||||
|
{ \
|
||||||
|
u32 GameTypeID = GetGameTypeID(Game, TypeEnum); \
|
||||||
|
auto Find = gTypeExtensionMap.find(GameTypeID); \
|
||||||
|
ASSERT(Find == gTypeExtensionMap.end()); \
|
||||||
|
gTypeExtensionMap[GameTypeID] = #CookedExtension; \
|
||||||
|
Game = (EGame) ((int) Game + 1); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
CResourceTypeRegistrant__##CookedExtension gResourceTypeRegistrant__##CookedExtension;
|
||||||
|
|
||||||
|
REGISTER_RESOURCE_TYPE(AFSM, eStateMachine, ePrimeDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(AGSC, eAudioGroupSet, ePrimeDemo, eCorruptionProto)
|
||||||
|
REGISTER_RESOURCE_TYPE(ANCS, eAnimSet, ePrimeDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(ANIM, eAnimation, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(ATBL, eAudioLookupTable, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(BFRC, eBurstFireData, eCorruptionProto, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(CAAD, eUnknown_CAAD, eCorruption, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(CAUD, eAudioMacro, eCorruptionProto, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CHAR, eCharacter, eCorruptionProto, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CINF, eSkeleton, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CMDL, eModel, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CRSC, eParticleCollisionResponse, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(CPRM, eAnimCollisionPrimData, eReturns, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CSKR, eSkin, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CSMP, eAudioSample, eCorruptionProto, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(CSNG, eMidi, ePrimeDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(CSPP, eSpatialPrimitive, eEchoesDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(CTWK, eTweak, ePrimeDemo, ePrime)
|
||||||
|
REGISTER_RESOURCE_TYPE(DCLN, eDynamicCollision, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(DGRP, eDependencyGroup, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(DPSC, eParticleDecal, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(DUMB, eBinaryData, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(EGMC, eStaticGeometryMap, eEchoesDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(ELSC, eParticleElectric, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(EVNT, eAnimEventData, ePrimeDemo, ePrime)
|
||||||
|
REGISTER_RESOURCE_TYPE(FONT, eFont, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(FRME, eGuiFrame, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(FSM2, eStateMachine2, eEchoesDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(FSMC, eStateMachine, eReturns, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(HINT, eHintSystem, ePrime, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(KFAM, eGuiKeyFrame, ePrimeDemo, ePrimeDemo)
|
||||||
|
REGISTER_RESOURCE_TYPE(MAPA, eMapArea, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(MAPU, eMapUniverse, ePrimeDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(MAPW, eMapWorld, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(MLVL, eWorld, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(MREA, eArea, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(NTWK, eTweak, eEchoesDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(PAK , ePackage, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(PART, eParticle, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(PATH, eNavMesh, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(PTLA, ePortalArea, eEchoesDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(RULE, eRuleSet, eEchoesDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(SAND, eSourceAnimData, eCorruptionProto, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(SAVA, eSaveArea, eCorruptionProto, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(SAVW, eSaveWorld, ePrime, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(SCAN, eScan, ePrimeDemo, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(SPSC, eParticleSpawn, eEchoesDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(SRSC, eParticleSorted, eEchoesDemo, eEchoes)
|
||||||
|
REGISTER_RESOURCE_TYPE(STLC, eStringList, eEchoesDemo, eCorruptionProto)
|
||||||
|
REGISTER_RESOURCE_TYPE(STRG, eStringTable, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(STRM, eStreamedAudio, eCorruptionProto, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(SWHC, eParticleSwoosh, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(THP , eVideo, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(TXTR, eTexture, ePrimeDemo, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(USRC, eUserEvaluatorData, eCorruptionProto, eCorruption)
|
||||||
|
REGISTER_RESOURCE_TYPE(XFSC, eParticleTransform, eReturns, eReturns)
|
||||||
|
REGISTER_RESOURCE_TYPE(WPSC, eParticleWeapon, ePrimeDemo, eCorruption)
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
// Global version enum that can be easily shared between loaders
|
// Global version enum that can be easily shared between loaders
|
||||||
enum EGame
|
enum EGame
|
||||||
{
|
{
|
||||||
ePrimeDemo = 0,
|
ePrimeDemo,
|
||||||
ePrime = 1,
|
ePrime,
|
||||||
eEchoesDemo = 2,
|
eEchoesDemo,
|
||||||
eEchoes = 3,
|
eEchoes,
|
||||||
eCorruptionProto = 4,
|
eCorruptionProto,
|
||||||
eCorruption = 5,
|
eCorruption,
|
||||||
eReturns = 6,
|
eReturns,
|
||||||
eUnknownVersion = -1
|
eUnknownVersion = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EGAME_H
|
#endif // EGAME_H
|
||||||
|
|
|
@ -1,52 +1,75 @@
|
||||||
#ifndef ERESTYPE
|
#ifndef ERESTYPE
|
||||||
#define ERESTYPE
|
#define ERESTYPE
|
||||||
|
|
||||||
|
#include "EGame.h"
|
||||||
|
#include <Common/TString.h>
|
||||||
|
|
||||||
enum EResType
|
enum EResType
|
||||||
{
|
{
|
||||||
eAnimation = 0,
|
eAnimation,
|
||||||
eAnimEventData = 1,
|
eAnimCollisionPrimData,
|
||||||
eAnimSet = 2,
|
eAnimEventData,
|
||||||
eArea = 3,
|
eAnimSet,
|
||||||
eAudioData = 4,
|
eArea,
|
||||||
eAudioGrp = 5,
|
eAudioMacro,
|
||||||
eAudioSample = 6,
|
eAudioGroupSet,
|
||||||
eAudioStream = 7,
|
eAudioSample,
|
||||||
eAudioTable = 8,
|
eStreamedAudio,
|
||||||
eCharacter = 9,
|
eAudioLookupTable,
|
||||||
eCollisionMeshGroup = 10,
|
eBinaryData,
|
||||||
eCollisionResponse = 11,
|
eBurstFireData,
|
||||||
eDataDump = 12,
|
eCharacter,
|
||||||
eDecal = 13,
|
eDependencyGroup,
|
||||||
eDependencyGroup = 14,
|
eDynamicCollision,
|
||||||
eFont = 15,
|
eFont,
|
||||||
eGuiFrame = 16,
|
eGuiFrame,
|
||||||
eHintSystem = 17,
|
eGuiKeyFrame,
|
||||||
eInvalidResType = 18,
|
eHintSystem,
|
||||||
eMapArea = 19,
|
eInvalidResType,
|
||||||
eMapWorld = 20,
|
eMapArea,
|
||||||
eMapUniverse = 21,
|
eMapWorld,
|
||||||
eMidi = 22,
|
eMapUniverse,
|
||||||
eModel = 23,
|
eMidi,
|
||||||
eMusicTrack = 24,
|
eModel,
|
||||||
eNavMesh = 25,
|
eMusicTrack,
|
||||||
ePackFile = 26,
|
eNavMesh,
|
||||||
eParticle = 27,
|
ePackage,
|
||||||
eParticleElectric = 28,
|
eParticle,
|
||||||
eParticleSwoosh = 29,
|
eParticleCollisionResponse,
|
||||||
ePoiToWorld = 30,
|
eParticleDecal,
|
||||||
eProjectile = 31,
|
eParticleElectric,
|
||||||
eResource = 32,
|
eParticleSorted,
|
||||||
eSaveWorld = 33,
|
eParticleSpawn,
|
||||||
eScan = 34,
|
eParticleSwoosh,
|
||||||
eSkeleton = 35,
|
eParticleTransform,
|
||||||
eSkin = 36,
|
eParticleWeapon,
|
||||||
eStateMachine = 37,
|
ePortalArea,
|
||||||
eStringTable = 38,
|
eResource,
|
||||||
eTexture = 39,
|
eRuleSet,
|
||||||
eTweak = 40,
|
eSaveArea,
|
||||||
eVideo = 41,
|
eSaveWorld,
|
||||||
eWorld = 42
|
eScan,
|
||||||
|
eSkeleton,
|
||||||
|
eSkin,
|
||||||
|
eSourceAnimData,
|
||||||
|
eSpatialPrimitive,
|
||||||
|
eStateMachine,
|
||||||
|
eStateMachine2, // For distinguishing AFSM/FSM2
|
||||||
|
eStaticGeometryMap,
|
||||||
|
eStringList,
|
||||||
|
eStringTable,
|
||||||
|
eTexture,
|
||||||
|
eTweak,
|
||||||
|
eUnknown_CAAD,
|
||||||
|
eUserEvaluatorData,
|
||||||
|
eVideo,
|
||||||
|
eWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// defined in CResource.cpp
|
||||||
|
TString GetTypeName(EResType Type);
|
||||||
|
TString GetRawExtension(EResType Type, EGame Game);
|
||||||
|
TString GetCookedExtension(EResType Type, EGame Game);
|
||||||
|
|
||||||
#endif // ERESTYPE
|
#endif // ERESTYPE
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify resource exists + is correct type
|
// Verify resource exists + is correct type
|
||||||
if (pRes && (pRes->Type() == eCollisionMeshGroup))
|
if (pRes && (pRes->Type() == eDynamicCollision))
|
||||||
return static_cast<CCollisionMeshGroup*>(pRes);
|
return static_cast<CCollisionMeshGroup*>(pRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -258,15 +258,19 @@ void CStartWindow::About()
|
||||||
void CStartWindow::ExportGame()
|
void CStartWindow::ExportGame()
|
||||||
{
|
{
|
||||||
// TEMP - hardcoded names for convenience. will remove later!
|
// TEMP - hardcoded names for convenience. will remove later!
|
||||||
#define USE_HARDCODED_NAMES 1
|
#define USE_HARDCODED_GAME_ROOT 0
|
||||||
|
#define USE_HARDCODED_EXPORT_DIR 1
|
||||||
|
|
||||||
#if USE_HARDCODED_NAMES
|
#if USE_HARDCODED_GAME_ROOT
|
||||||
QString GameRoot = "E:/Unpacked/DKCR Dolphin";
|
QString GameRoot = "E:/Unpacked/Metroid Prime 2";
|
||||||
QString ExportDir = "E:/Unpacked/ExportTest";
|
|
||||||
#else
|
#else
|
||||||
QString GameRoot = QFileDialog::getExistingDirectory(this, "Select game root directory");
|
QString GameRoot = QFileDialog::getExistingDirectory(this, "Select game root directory");
|
||||||
if (GameRoot.isEmpty()) return;
|
if (GameRoot.isEmpty()) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_HARDCODED_EXPORT_DIR
|
||||||
|
QString ExportDir = "E:/Unpacked/ExportTest";
|
||||||
|
#else
|
||||||
QString ExportDir = QFileDialog::getExistingDirectory(this, "Select output export directory");
|
QString ExportDir = QFileDialog::getExistingDirectory(this, "Select output export directory");
|
||||||
if (ExportDir.isEmpty()) return;
|
if (ExportDir.isEmpty()) return;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue