Fixed some missed dependencies in a few formats and implemented support for building file lists for paks and MLVLs, and implemented support for package cooking for MP1
This commit is contained in:
parent
0f2c0d5b39
commit
de18044ae0
|
@ -38,6 +38,14 @@ CAssetID::CAssetID(const char* pkID)
|
||||||
*this = CAssetID::FromString(pkID);
|
*this = CAssetID::FromString(pkID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CAssetID::Write(IOutputStream& rOutput) const
|
||||||
|
{
|
||||||
|
if (mLength == e32Bit)
|
||||||
|
rOutput.WriteLong(ToLong());
|
||||||
|
else
|
||||||
|
rOutput.WriteLongLong(ToLongLong());
|
||||||
|
}
|
||||||
|
|
||||||
CAssetID::CAssetID(IInputStream& rInput, EIDLength Length)
|
CAssetID::CAssetID(IInputStream& rInput, EIDLength Length)
|
||||||
: mLength(Length)
|
: mLength(Length)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@ public:
|
||||||
CAssetID(u64 ID, EIDLength Length);
|
CAssetID(u64 ID, EIDLength Length);
|
||||||
CAssetID(const char* pkID);
|
CAssetID(const char* pkID);
|
||||||
CAssetID(IInputStream& rInput, EIDLength Length);
|
CAssetID(IInputStream& rInput, EIDLength Length);
|
||||||
|
void Write(IOutputStream& rOutput) const;
|
||||||
TString ToString() const;
|
TString ToString() const;
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
if (rInput.GetEndianness() == IOUtil::eLittleEndian) Reverse();
|
if (rInput.GetEndianness() == IOUtil::eLittleEndian) Reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Write(IOutputStream& rOutput)
|
inline void Write(IOutputStream& rOutput) const
|
||||||
{
|
{
|
||||||
u32 Val = mFourCC;
|
u32 Val = mFourCC;
|
||||||
if (rOutput.GetEndianness() == IOUtil::eLittleEndian) IOUtil::SwapBytes(Val);
|
if (rOutput.GetEndianness() == IOUtil::eLittleEndian) IOUtil::SwapBytes(Val);
|
||||||
|
|
|
@ -203,7 +203,8 @@ HEADERS += \
|
||||||
Resource/ParticleParameters.h \
|
Resource/ParticleParameters.h \
|
||||||
Resource/Factory/CUnsupportedParticleLoader.h \
|
Resource/Factory/CUnsupportedParticleLoader.h \
|
||||||
Resource/Resources.h \
|
Resource/Resources.h \
|
||||||
Resource/Factory/CResourceFactory.h
|
Resource/Factory/CResourceFactory.h \
|
||||||
|
GameProject/DependencyListBuilders.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
|
|
@ -115,16 +115,15 @@ CAssetID CDependencyTree::DependencyByIndex(u32 Index) const
|
||||||
return mReferencedResources[Index]->ID();
|
return mReferencedResources[Index]->ID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(CResource *pRes)
|
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
|
||||||
{
|
{
|
||||||
if (!pRes || HasDependency(pRes->ID())) return;
|
if (!pRes) return;
|
||||||
CResourceDependency *pDepend = new CResourceDependency(pRes->ID());
|
AddDependency(pRes->ID(), AvoidDuplicates);
|
||||||
mReferencedResources.push_back(pDepend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(const CAssetID& rkID)
|
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
|
||||||
{
|
{
|
||||||
if (!rkID.IsValid() || HasDependency(rkID)) return;
|
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID))) return;
|
||||||
CResourceDependency *pDepend = new CResourceDependency(rkID);
|
CResourceDependency *pDepend = new CResourceDependency(rkID);
|
||||||
mReferencedResources.push_back(pDepend);
|
mReferencedResources.push_back(pDepend);
|
||||||
}
|
}
|
||||||
|
@ -154,14 +153,15 @@ void CAnimSetDependencyTree::Write(IOutputStream& rFile, EIDLength IDLength) con
|
||||||
rFile.WriteLong( mCharacterOffsets[iChar] );
|
rFile.WriteLong( mCharacterOffsets[iChar] );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar)
|
void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar, const std::set<CAssetID>& rkBaseUsedSet)
|
||||||
{
|
{
|
||||||
mCharacterOffsets.push_back( NumDependencies() );
|
mCharacterOffsets.push_back( NumDependencies() );
|
||||||
if (!pkChar) return;
|
if (!pkChar) return;
|
||||||
|
|
||||||
AddDependency(pkChar->pModel);
|
std::set<CAssetID> UsedSet = rkBaseUsedSet;
|
||||||
AddDependency(pkChar->pSkeleton);
|
AddCharDependency(pkChar->pModel, UsedSet);
|
||||||
AddDependency(pkChar->pSkin);
|
AddCharDependency(pkChar->pSkeleton, UsedSet);
|
||||||
|
AddCharDependency(pkChar->pSkin, UsedSet);
|
||||||
|
|
||||||
const std::vector<CAssetID> *pkParticleVectors[5] = {
|
const std::vector<CAssetID> *pkParticleVectors[5] = {
|
||||||
&pkChar->GenericParticles, &pkChar->ElectricParticles,
|
&pkChar->GenericParticles, &pkChar->ElectricParticles,
|
||||||
|
@ -172,11 +172,26 @@ void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar)
|
||||||
for (u32 iVec = 0; iVec < 5; iVec++)
|
for (u32 iVec = 0; iVec < 5; iVec++)
|
||||||
{
|
{
|
||||||
for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
|
for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
|
||||||
AddDependency(pkParticleVectors[iVec]->at(iPart));
|
AddCharDependency(pkParticleVectors[iVec]->at(iPart), UsedSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDependency(pkChar->IceModel);
|
AddCharDependency(pkChar->IceModel, UsedSet);
|
||||||
AddDependency(pkChar->IceSkin);
|
AddCharDependency(pkChar->IceSkin, UsedSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependencyTree::AddCharDependency(const CAssetID& rkID, std::set<CAssetID>& rUsedSet)
|
||||||
|
{
|
||||||
|
if (rkID.IsValid() && rUsedSet.find(rkID) == rUsedSet.end())
|
||||||
|
{
|
||||||
|
rUsedSet.insert(rkID);
|
||||||
|
AddDependency(rkID, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependencyTree::AddCharDependency(CResource *pRes, std::set<CAssetID>& rUsedSet)
|
||||||
|
{
|
||||||
|
if (!pRes) return;
|
||||||
|
AddCharDependency(pRes->ID(), rUsedSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CScriptInstanceDependencyTree ************
|
// ************ CScriptInstanceDependencyTree ************
|
||||||
|
@ -240,6 +255,12 @@ bool CScriptInstanceDependencyTree::HasDependency(const CAssetID& rkID)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CAssetID CScriptInstanceDependencyTree::DependencyByIndex(u32 Index) const
|
||||||
|
{
|
||||||
|
ASSERT(Index >= 0 && Index < mDependencies.size());
|
||||||
|
return mDependencies[Index]->ID();
|
||||||
|
}
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
CScriptInstanceDependencyTree* CScriptInstanceDependencyTree::BuildTree(CScriptObject *pInstance)
|
CScriptInstanceDependencyTree* CScriptInstanceDependencyTree::BuildTree(CScriptObject *pInstance)
|
||||||
{
|
{
|
||||||
|
@ -343,3 +364,9 @@ void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer)
|
||||||
delete pTree;
|
delete pTree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CScriptInstanceDependencyTree* CAreaDependencyTree::ScriptInstanceByIndex(u32 Index) const
|
||||||
|
{
|
||||||
|
ASSERT(Index >= 0 && Index < mScriptInstances.size());
|
||||||
|
return mScriptInstances[Index];
|
||||||
|
}
|
||||||
|
|
|
@ -90,8 +90,8 @@ public:
|
||||||
u32 NumDependencies() const;
|
u32 NumDependencies() const;
|
||||||
bool HasDependency(const CAssetID& rkID);
|
bool HasDependency(const CAssetID& rkID);
|
||||||
CAssetID DependencyByIndex(u32 Index) const;
|
CAssetID DependencyByIndex(u32 Index) const;
|
||||||
void AddDependency(const CAssetID& rkID);
|
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
|
||||||
void AddDependency(CResource *pRes);
|
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline void SetID(const CAssetID& rkID) { mID = rkID; }
|
inline void SetID(const CAssetID& rkID) { mID = rkID; }
|
||||||
|
@ -111,7 +111,13 @@ public:
|
||||||
virtual void Read(IInputStream& rFile, EIDLength IDLength);
|
virtual void Read(IInputStream& rFile, EIDLength IDLength);
|
||||||
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
||||||
|
|
||||||
void AddCharacter(const SSetCharacter *pkChar);
|
void AddCharacter(const SSetCharacter *pkChar, const std::set<CAssetID>& rkBaseUsedSet);
|
||||||
|
void AddCharDependency(const CAssetID& rkID, std::set<CAssetID>& rUsedSet);
|
||||||
|
void AddCharDependency(CResource *pRes, std::set<CAssetID>& rUsedSet);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline u32 NumCharacters() const { return mCharacterOffsets.size(); }
|
||||||
|
inline u32 CharacterOffset(u32 CharIdx) const { return mCharacterOffsets[CharIdx]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing a script object. Indicates the type of object.
|
// Node representing a script object. Indicates the type of object.
|
||||||
|
@ -128,9 +134,11 @@ public:
|
||||||
virtual void Read(IInputStream& rFile, EIDLength IDLength);
|
virtual void Read(IInputStream& rFile, EIDLength IDLength);
|
||||||
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
||||||
bool HasDependency(const CAssetID& rkID);
|
bool HasDependency(const CAssetID& rkID);
|
||||||
|
CAssetID DependencyByIndex(u32 Index) const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
u32 NumDependencies() const { return mDependencies.size(); }
|
inline u32 NumDependencies() const { return mDependencies.size(); }
|
||||||
|
inline u32 ObjectType() const { return mObjectType; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CScriptInstanceDependencyTree* BuildTree(CScriptObject *pInstance);
|
static CScriptInstanceDependencyTree* BuildTree(CScriptObject *pInstance);
|
||||||
|
@ -153,6 +161,12 @@ public:
|
||||||
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
|
||||||
|
|
||||||
void AddScriptLayer(CScriptLayer *pLayer);
|
void AddScriptLayer(CScriptLayer *pLayer);
|
||||||
|
CScriptInstanceDependencyTree* ScriptInstanceByIndex(u32 Index) const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline u32 NumScriptLayers() const { return mLayerOffsets.size(); }
|
||||||
|
inline u32 NumScriptInstances() const { return mScriptInstances.size(); }
|
||||||
|
inline u32 ScriptLayerOffset(u32 LayerIdx) const { return mLayerOffsets[LayerIdx]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CDEPENDENCYTREE
|
#endif // CDEPENDENCYTREE
|
||||||
|
|
|
@ -148,7 +148,7 @@ void CGameExporter::LoadAssetList()
|
||||||
|
|
||||||
while (pAsset)
|
while (pAsset)
|
||||||
{
|
{
|
||||||
u64 ResourceID = TString(pAsset->Attribute("ID")).ToInt64(16);
|
CAssetID ResourceID = TString(pAsset->Attribute("ID")).ToInt64(16);
|
||||||
|
|
||||||
tinyxml2::XMLElement *pDir = pAsset->FirstChildElement("Dir");
|
tinyxml2::XMLElement *pDir = pAsset->FirstChildElement("Dir");
|
||||||
TString Dir = pDir ? pDir->GetText() : "";
|
TString Dir = pDir ? pDir->GetText() : "";
|
||||||
|
@ -206,11 +206,15 @@ void CGameExporter::LoadPaks()
|
||||||
u32 NameLen = Pak.ReadLong();
|
u32 NameLen = Pak.ReadLong();
|
||||||
TString Name = Pak.ReadString(NameLen);
|
TString Name = Pak.ReadString(NameLen);
|
||||||
pCollection->AddResource(Name, ResID, ResType);
|
pCollection->AddResource(Name, ResID, ResType);
|
||||||
SetResourcePath(ResID.ToLongLong(), PakName + L"\\", Name.ToUTF16());
|
SetResourcePath(ResID, PakName + L"\\", Name.ToUTF16());
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 NumResources = Pak.ReadLong();
|
u32 NumResources = Pak.ReadLong();
|
||||||
|
|
||||||
|
// Keep track of which areas have duplicate resources
|
||||||
|
std::set<CAssetID> PakResourceSet;
|
||||||
|
bool AreaHasDuplicates = true; // Default to true so that first area is always considered as having duplicates
|
||||||
|
|
||||||
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
bool Compressed = (Pak.ReadLong() == 1);
|
bool Compressed = (Pak.ReadLong() == 1);
|
||||||
|
@ -219,9 +223,21 @@ void CGameExporter::LoadPaks()
|
||||||
u32 ResSize = Pak.ReadLong();
|
u32 ResSize = Pak.ReadLong();
|
||||||
u32 ResOffset = Pak.ReadLong();
|
u32 ResOffset = Pak.ReadLong();
|
||||||
|
|
||||||
u64 IntegralID = ResID.ToLongLong();
|
if (mResourceMap.find(ResID) == mResourceMap.end())
|
||||||
if (mResourceMap.find(IntegralID) == mResourceMap.end())
|
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false };
|
||||||
mResourceMap[IntegralID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false };
|
|
||||||
|
// Check for duplicate resources
|
||||||
|
if (ResType == "MREA")
|
||||||
|
{
|
||||||
|
mAreaDuplicateMap[ResID] = AreaHasDuplicates;
|
||||||
|
AreaHasDuplicates = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end())
|
||||||
|
AreaHasDuplicates = true;
|
||||||
|
|
||||||
|
else
|
||||||
|
PakResourceSet.insert(ResID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +281,7 @@ void CGameExporter::LoadPaks()
|
||||||
CFourCC ResType = Pak.ReadLong();
|
CFourCC ResType = Pak.ReadLong();
|
||||||
CAssetID ResID(Pak, IDLength);
|
CAssetID ResID(Pak, IDLength);
|
||||||
pCollection->AddResource(Name, ResID, ResType);
|
pCollection->AddResource(Name, ResID, ResType);
|
||||||
SetResourcePath(ResID.ToLongLong(), PakName + L"\\", Name.ToUTF16());
|
SetResourcePath(ResID, PakName + L"\\", Name.ToUTF16());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +291,10 @@ void CGameExporter::LoadPaks()
|
||||||
u32 DataStart = Next;
|
u32 DataStart = Next;
|
||||||
u32 NumResources = Pak.ReadLong();
|
u32 NumResources = Pak.ReadLong();
|
||||||
|
|
||||||
|
// Keep track of which areas have duplicate resources
|
||||||
|
std::set<CAssetID> PakResourceSet;
|
||||||
|
bool AreaHasDuplicates = true; // Default to true so that first area is always considered as having duplicates
|
||||||
|
|
||||||
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
bool Compressed = (Pak.ReadLong() == 1);
|
bool Compressed = (Pak.ReadLong() == 1);
|
||||||
|
@ -283,9 +303,24 @@ void CGameExporter::LoadPaks()
|
||||||
u32 Size = Pak.ReadLong();
|
u32 Size = Pak.ReadLong();
|
||||||
u32 Offset = DataStart + Pak.ReadLong();
|
u32 Offset = DataStart + Pak.ReadLong();
|
||||||
|
|
||||||
u64 IntegralID = ResID.ToLongLong();
|
if (mResourceMap.find(ResID) == mResourceMap.end())
|
||||||
if (mResourceMap.find(IntegralID) == mResourceMap.end())
|
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
|
||||||
mResourceMap[IntegralID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
|
|
||||||
|
// Check for duplicate resources (unnecessary for DKCR)
|
||||||
|
if (Game() != eReturns)
|
||||||
|
{
|
||||||
|
if (Type == "MREA")
|
||||||
|
{
|
||||||
|
mAreaDuplicateMap[ResID] = AreaHasDuplicates;
|
||||||
|
AreaHasDuplicates = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end())
|
||||||
|
AreaHasDuplicates = true;
|
||||||
|
|
||||||
|
else
|
||||||
|
PakResourceSet.insert(ResID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +540,25 @@ void CGameExporter::ExportCookedResources()
|
||||||
for (CResourceIterator It(&mStore); It; ++It)
|
for (CResourceIterator It(&mStore); It; ++It)
|
||||||
{
|
{
|
||||||
if (!It->IsTransient())
|
if (!It->IsTransient())
|
||||||
|
{
|
||||||
|
// Worlds need to know which areas can have duplicates. We only have this info at export time.
|
||||||
|
if (It->ResourceType() == eWorld)
|
||||||
|
{
|
||||||
|
CWorld *pWorld = (CWorld*) It->Load();
|
||||||
|
|
||||||
|
for (u32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
||||||
|
{
|
||||||
|
CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
||||||
|
auto Find = mAreaDuplicateMap.find(AreaID);
|
||||||
|
|
||||||
|
if (Find != mAreaDuplicateMap.end())
|
||||||
|
pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save raw resource + cache data
|
||||||
It->Save();
|
It->Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ class CGameExporter
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
TWideStringList mPaks;
|
TWideStringList mPaks;
|
||||||
|
std::map<CAssetID, bool> mAreaDuplicateMap;
|
||||||
|
|
||||||
struct SResourceInstance
|
struct SResourceInstance
|
||||||
{
|
{
|
||||||
|
@ -37,14 +38,14 @@ class CGameExporter
|
||||||
bool Compressed;
|
bool Compressed;
|
||||||
bool Exported;
|
bool Exported;
|
||||||
};
|
};
|
||||||
std::map<u64, SResourceInstance> mResourceMap;
|
std::map<CAssetID, SResourceInstance> mResourceMap;
|
||||||
|
|
||||||
struct SResourcePath
|
struct SResourcePath
|
||||||
{
|
{
|
||||||
TWideString Dir;
|
TWideString Dir;
|
||||||
TWideString Name;
|
TWideString Name;
|
||||||
};
|
};
|
||||||
std::map<u64, SResourcePath> mResourcePaths;
|
std::map<CAssetID, SResourcePath> mResourcePaths;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGameExporter(const TString& rkInputDir, const TString& rkOutputDir);
|
CGameExporter(const TString& rkInputDir, const TString& rkOutputDir);
|
||||||
|
@ -77,12 +78,7 @@ protected:
|
||||||
|
|
||||||
inline void SetResourcePath(const CAssetID& rkID, const TWideString& rkDir, const TWideString& rkName)
|
inline void SetResourcePath(const CAssetID& rkID, const TWideString& rkDir, const TWideString& rkName)
|
||||||
{
|
{
|
||||||
SetResourcePath(rkID.ToLongLong(), rkDir, rkName);
|
mResourcePaths[rkID] = SResourcePath { rkDir, rkName };
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetResourcePath(u64 ID, const TWideString& rkDir, const TWideString& rkName)
|
|
||||||
{
|
|
||||||
mResourcePaths[ID] = SResourcePath { rkDir, rkName };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EGame Game() const { return mpProject->Game(); }
|
inline EGame Game() const { return mpProject->Game(); }
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#include "CPackage.h"
|
#include "CPackage.h"
|
||||||
|
#include "DependencyListBuilders.h"
|
||||||
#include "CGameProject.h"
|
#include "CGameProject.h"
|
||||||
|
#include "Core/Resource/Cooker/CWorldCooker.h"
|
||||||
|
#include <FileIO/FileIO.h>
|
||||||
#include <Common/AssertMacro.h>
|
#include <Common/AssertMacro.h>
|
||||||
|
#include <Common/CompressionUtil.h>
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
@ -106,6 +110,244 @@ void CPackage::Save()
|
||||||
Log::Error("Failed to save pak definition at path: " + DefPath.ToUTF8());
|
Log::Error("Failed to save pak definition at path: " + DefPath.ToUTF8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPackage::Cook()
|
||||||
|
{
|
||||||
|
// Build asset list
|
||||||
|
CPackageDependencyListBuilder Builder(this);
|
||||||
|
std::list<CAssetID> AssetList;
|
||||||
|
Builder.BuildDependencyList(true, AssetList);
|
||||||
|
Log::Write(TString::FromInt32(AssetList.size(), 0, 10) + " assets in pak");
|
||||||
|
|
||||||
|
// Get named resources
|
||||||
|
std::list<const SNamedResource*> NamedResources;
|
||||||
|
|
||||||
|
for (u32 iCol = 0; iCol < mCollections.size(); iCol++)
|
||||||
|
{
|
||||||
|
CResourceCollection *pCol = mCollections[iCol];
|
||||||
|
|
||||||
|
for (u32 iRes = 0; iRes < pCol->NumResources(); iRes++)
|
||||||
|
NamedResources.push_back(&pCol->ResourceByIndex(iRes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write new pak
|
||||||
|
TWideString PakPath = CookedPackagePath(false);
|
||||||
|
CFileOutStream Pak(PakPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
|
||||||
|
|
||||||
|
if (!Pak.IsValid())
|
||||||
|
{
|
||||||
|
Log::Error("Couldn't cook package " + CookedPackagePath(true).ToUTF8() + "; unable to open package for writing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: MP3/DKCR pak format support
|
||||||
|
Pak.WriteLong(0x00030005); // Major/Minor Version
|
||||||
|
Pak.WriteLong(0); // Unknown
|
||||||
|
|
||||||
|
// Named Resources
|
||||||
|
Pak.WriteLong(NamedResources.size());
|
||||||
|
|
||||||
|
for (auto Iter = NamedResources.begin(); Iter != NamedResources.end(); Iter++)
|
||||||
|
{
|
||||||
|
const SNamedResource *pkRes = *Iter;
|
||||||
|
pkRes->Type.Write(Pak);
|
||||||
|
pkRes->ID.Write(Pak);
|
||||||
|
Pak.WriteLong(pkRes->Name.Size());
|
||||||
|
Pak.WriteString(pkRes->Name.ToStdString(), pkRes->Name.Size()); // Note: Explicitly specifying size means we don't write the terminating 0
|
||||||
|
|
||||||
|
// TEMP: recook world
|
||||||
|
if (pkRes->Type == "MLVL")
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(pkRes->ID);
|
||||||
|
ASSERT(pEntry);
|
||||||
|
CWorld *pWorld = (CWorld*) pEntry->Load();
|
||||||
|
ASSERT(pWorld);
|
||||||
|
CFileOutStream MLVL(pEntry->CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
|
||||||
|
ASSERT(MLVL.IsValid());
|
||||||
|
CWorldCooker::CookMLVL(pWorld, MLVL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in table of contents with junk, write later
|
||||||
|
Pak.WriteLong(AssetList.size());
|
||||||
|
u32 TocOffset = Pak.Tell();
|
||||||
|
|
||||||
|
for (u32 iRes = 0; iRes < AssetList.size(); iRes++)
|
||||||
|
{
|
||||||
|
Pak.WriteLongLong(0);
|
||||||
|
Pak.WriteLongLong(0);
|
||||||
|
Pak.WriteLong(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pak.WriteToBoundary(32, 0);
|
||||||
|
|
||||||
|
// Start writing resources
|
||||||
|
struct SResourceTocInfo
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry;
|
||||||
|
u32 Offset;
|
||||||
|
u32 Size;
|
||||||
|
bool Compressed;
|
||||||
|
};
|
||||||
|
std::vector<SResourceTocInfo> ResourceTocData(AssetList.size());
|
||||||
|
u32 ResIdx = 0;
|
||||||
|
|
||||||
|
for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++, ResIdx++)
|
||||||
|
{
|
||||||
|
CAssetID ID = *Iter;
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
|
ASSERT(pEntry != nullptr);
|
||||||
|
|
||||||
|
SResourceTocInfo& rTocInfo = ResourceTocData[ResIdx];
|
||||||
|
rTocInfo.pEntry = pEntry;
|
||||||
|
rTocInfo.Offset = Pak.Tell();
|
||||||
|
|
||||||
|
// Load resource data
|
||||||
|
CFileInStream CookedAsset(pEntry->CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
|
||||||
|
ASSERT(CookedAsset.IsValid());
|
||||||
|
u32 ResourceSize = CookedAsset.Size();
|
||||||
|
|
||||||
|
std::vector<u8> ResourceData(ResourceSize);
|
||||||
|
CookedAsset.ReadBytes(ResourceData.data(), ResourceData.size());
|
||||||
|
|
||||||
|
// Check if this asset should be compressed; there are a few resource types that are
|
||||||
|
// always compressed, and some types that are compressed if they're over a certain size
|
||||||
|
EResType Type = pEntry->ResourceType();
|
||||||
|
|
||||||
|
bool ShouldAlwaysCompress = (Type == eTexture || Type == eModel || Type == eSkin ||
|
||||||
|
Type == eAnimSet || Type == eAnimation || Type == eFont);
|
||||||
|
|
||||||
|
bool ShouldCompressConditional = !ShouldAlwaysCompress &&
|
||||||
|
(Type == eParticle || Type == eParticleElectric || Type == eParticleSwoosh ||
|
||||||
|
Type == eParticleWeapon || Type == eParticleDecal || Type == eParticleCollisionResponse);
|
||||||
|
|
||||||
|
bool ShouldCompress = ShouldAlwaysCompress || (ShouldCompressConditional && ResourceSize >= 0x400);
|
||||||
|
|
||||||
|
// Write resource data to pak
|
||||||
|
if (!ShouldCompress)
|
||||||
|
{
|
||||||
|
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
||||||
|
rTocInfo.Compressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 CompressedSize;
|
||||||
|
std::vector<u8> CompressedData(ResourceData.size() * 2);
|
||||||
|
bool Success = CompressionUtil::CompressZlib(ResourceData.data(), ResourceData.size(), CompressedData.data(), CompressedData.size(), CompressedSize);
|
||||||
|
|
||||||
|
// Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value
|
||||||
|
if (Success)
|
||||||
|
{
|
||||||
|
u32 PaddedUncompressedSize = (ResourceSize + 0x1F) & ~0x1F;
|
||||||
|
u32 PaddedCompressedSize = (CompressedSize + 4 + 0x1F) & ~0x1F;
|
||||||
|
Success = (PaddedCompressedSize < PaddedUncompressedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file to pak
|
||||||
|
if (Success)
|
||||||
|
{
|
||||||
|
Pak.WriteLong(ResourceSize);
|
||||||
|
Pak.WriteBytes(CompressedData.data(), CompressedSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
||||||
|
|
||||||
|
rTocInfo.Compressed = Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pak.WriteToBoundary(32, 0xFF);
|
||||||
|
rTocInfo.Size = Pak.Tell() - rTocInfo.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write table of contents for real
|
||||||
|
Pak.Seek(TocOffset, SEEK_SET);
|
||||||
|
|
||||||
|
for (u32 iRes = 0; iRes < AssetList.size(); iRes++)
|
||||||
|
{
|
||||||
|
const SResourceTocInfo& rkTocInfo = ResourceTocData[iRes];
|
||||||
|
CResourceEntry *pEntry = rkTocInfo.pEntry;
|
||||||
|
|
||||||
|
Pak.WriteLong( rkTocInfo.Compressed ? 1 : 0 );
|
||||||
|
pEntry->CookedExtension().Write(Pak);
|
||||||
|
pEntry->ID().Write(Pak);
|
||||||
|
Pak.WriteLong(rkTocInfo.Size);
|
||||||
|
Pak.WriteLong(rkTocInfo.Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::Write("Finished writing " + PakPath.ToUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPackage::CompareOriginalAssetList(const std::list<CAssetID>& rkNewList)
|
||||||
|
{
|
||||||
|
// Debug - take the newly generated rkNewList and compare it with the asset list
|
||||||
|
// from the original pak, and print info about any extra or missing resources
|
||||||
|
// Build a set out of the generated list
|
||||||
|
std::set<CAssetID> NewListSet;
|
||||||
|
|
||||||
|
for (auto Iter = rkNewList.begin(); Iter != rkNewList.end(); Iter++)
|
||||||
|
NewListSet.insert(*Iter);
|
||||||
|
|
||||||
|
// Read the original pak
|
||||||
|
TWideString CookedPath = CookedPackagePath(false);
|
||||||
|
CFileInStream Pak(CookedPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
|
||||||
|
|
||||||
|
if (!Pak.IsValid())
|
||||||
|
{
|
||||||
|
Log::Error("Failed to compare to original asset list; couldn't open the original pak");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip past header + named resources
|
||||||
|
u32 PakVersion = Pak.ReadLong();
|
||||||
|
ASSERT(PakVersion == 0x00030005);
|
||||||
|
Pak.Seek(0x4, SEEK_CUR);
|
||||||
|
u32 NumNamedResources = Pak.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iName = 0; iName < NumNamedResources; iName++)
|
||||||
|
{
|
||||||
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
|
u32 NameLen = Pak.ReadLong();
|
||||||
|
Pak.Seek(NameLen, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a set out of the original pak resource list
|
||||||
|
u32 NumResources = Pak.ReadLong();
|
||||||
|
std::set<CAssetID> OldListSet;
|
||||||
|
|
||||||
|
for (u32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
|
{
|
||||||
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
|
OldListSet.insert( CAssetID(Pak, e32Bit) );
|
||||||
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing resources in the new list
|
||||||
|
for (auto Iter = OldListSet.begin(); Iter != OldListSet.end(); Iter++)
|
||||||
|
{
|
||||||
|
CAssetID ID = *Iter;
|
||||||
|
|
||||||
|
if (NewListSet.find(ID) == NewListSet.end())
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
|
TString Extension = (pEntry ? "." + GetResourceCookedExtension(pEntry->ResourceType(), pEntry->Game()) : "");
|
||||||
|
Log::Error("Missing resource: " + ID.ToString() + Extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for extra resources in the new list
|
||||||
|
for (auto Iter = NewListSet.begin(); Iter != NewListSet.end(); Iter++)
|
||||||
|
{
|
||||||
|
CAssetID ID = *Iter;
|
||||||
|
|
||||||
|
if (OldListSet.find(ID) == OldListSet.end())
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
|
TString Extension = (pEntry ? "." + GetResourceCookedExtension(pEntry->ResourceType(), pEntry->Game()) : "");
|
||||||
|
Log::Error("Extra resource: " + ID.ToString() + Extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TWideString CPackage::DefinitionPath(bool Relative) const
|
TWideString CPackage::DefinitionPath(bool Relative) const
|
||||||
{
|
{
|
||||||
return mpProject->PackagesDir(Relative) + mPakPath + mPakName.ToUTF16() + L".pkd";
|
return mpProject->PackagesDir(Relative) + mPakPath + mPakName.ToUTF16() + L".pkd";
|
||||||
|
|
|
@ -60,6 +60,9 @@ public:
|
||||||
void Load();
|
void Load();
|
||||||
void Save();
|
void Save();
|
||||||
|
|
||||||
|
void Cook();
|
||||||
|
void CompareOriginalAssetList(const std::list<CAssetID>& rkNewList);
|
||||||
|
|
||||||
TWideString DefinitionPath(bool Relative) const;
|
TWideString DefinitionPath(bool Relative) const;
|
||||||
TWideString CookedPackagePath(bool Relative) const;
|
TWideString CookedPackagePath(bool Relative) const;
|
||||||
|
|
||||||
|
@ -70,6 +73,7 @@ public:
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString Name() const { return mPakName; }
|
inline TString Name() const { return mPakName; }
|
||||||
inline TWideString Path() const { return mPakPath; }
|
inline TWideString Path() const { return mPakPath; }
|
||||||
|
inline CGameProject* Project() const { return mpProject; }
|
||||||
inline u32 NumCollections() const { return mCollections.size(); }
|
inline u32 NumCollections() const { return mCollections.size(); }
|
||||||
inline CResourceCollection* CollectionByIndex(u32 Idx) const { return mCollections[Idx]; }
|
inline CResourceCollection* CollectionByIndex(u32 Idx) const { return mCollections[Idx]; }
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ bool CResourceEntry::LoadCacheData()
|
||||||
|
|
||||||
// Dependency Tree
|
// Dependency Tree
|
||||||
u32 DepsTreeSize = File.ReadLong();
|
u32 DepsTreeSize = File.ReadLong();
|
||||||
|
u32 DepsTreeStart = File.Tell();
|
||||||
|
|
||||||
if (mpDependencies)
|
if (mpDependencies)
|
||||||
{
|
{
|
||||||
|
@ -63,8 +64,12 @@ bool CResourceEntry::LoadCacheData()
|
||||||
|
|
||||||
if (DepsTreeSize > 0)
|
if (DepsTreeSize > 0)
|
||||||
{
|
{
|
||||||
mpDependencies = new CDependencyTree(mID);
|
if (mType == eArea) mpDependencies = new CAreaDependencyTree(mID);
|
||||||
|
else if (mType == eAnimSet) mpDependencies = new CAnimSetDependencyTree(mID);
|
||||||
|
else mpDependencies = new CDependencyTree(mID);
|
||||||
|
|
||||||
mpDependencies->Read(File, Game() <= eEchoes ? e32Bit : e64Bit);
|
mpDependencies->Read(File, Game() <= eEchoes ? e32Bit : e64Bit);
|
||||||
|
ASSERT(File.Tell() - DepsTreeStart == DepsTreeSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -166,6 +171,11 @@ TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||||
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
|
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFourCC CResourceEntry::CookedExtension() const
|
||||||
|
{
|
||||||
|
return CFourCC( GetResourceCookedExtension(mType, mGame) );
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pParentDir = mpDirectory;
|
CVirtualDirectory *pParentDir = mpDirectory;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "CVirtualDirectory.h"
|
#include "CVirtualDirectory.h"
|
||||||
#include "Core/Resource/EResType.h"
|
#include "Core/Resource/EResType.h"
|
||||||
#include <Common/CAssetID.h>
|
#include <Common/CAssetID.h>
|
||||||
|
#include <Common/CFourCC.h>
|
||||||
#include <Common/Flags.h>
|
#include <Common/Flags.h>
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
bool HasCookedVersion() const;
|
bool HasCookedVersion() const;
|
||||||
TString RawAssetPath(bool Relative = false) const;
|
TString RawAssetPath(bool Relative = false) const;
|
||||||
TString CookedAssetPath(bool Relative = false) const;
|
TString CookedAssetPath(bool Relative = false) const;
|
||||||
|
CFourCC CookedExtension() const;
|
||||||
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
||||||
u64 Size() const;
|
u64 Size() const;
|
||||||
bool NeedsRecook() const;
|
bool NeedsRecook() const;
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
#ifndef DEPENDENCYLISTBUILDERS
|
||||||
|
#define DEPENDENCYLISTBUILDERS
|
||||||
|
|
||||||
|
#include "CDependencyTree.h"
|
||||||
|
#include "CPackage.h"
|
||||||
|
#include "CResourceEntry.h"
|
||||||
|
#include "Core/Resource/CDependencyGroup.h"
|
||||||
|
#include "Core/Resource/CWorld.h"
|
||||||
|
|
||||||
|
// ************ CPackageDependencyListBuilder ************
|
||||||
|
class CPackageDependencyListBuilder
|
||||||
|
{
|
||||||
|
CPackage *mpPackage;
|
||||||
|
TResPtr<CWorld> mpWorld;
|
||||||
|
std::set<CAssetID> mPackageUsedAssets;
|
||||||
|
std::set<CAssetID> mAreaUsedAssets;
|
||||||
|
std::list<CAssetID> mScanIDs;
|
||||||
|
bool mEnableDuplicates;
|
||||||
|
bool mCurrentAreaHasDuplicates;
|
||||||
|
bool mAddingScans;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CPackageDependencyListBuilder(CPackage *pPackage)
|
||||||
|
: mpPackage(pPackage)
|
||||||
|
, mCurrentAreaHasDuplicates(false)
|
||||||
|
, mAddingScans(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void BuildDependencyList(bool AllowDuplicates, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
mEnableDuplicates = AllowDuplicates;
|
||||||
|
|
||||||
|
for (u32 iCol = 0; iCol < mpPackage->NumCollections(); iCol++)
|
||||||
|
{
|
||||||
|
CResourceCollection *pCollection = mpPackage->CollectionByIndex(iCol);
|
||||||
|
|
||||||
|
for (u32 iRes = 0; iRes < pCollection->NumResources(); iRes++)
|
||||||
|
{
|
||||||
|
const SNamedResource& rkRes = pCollection->ResourceByIndex(iRes);
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(rkRes.ID);
|
||||||
|
|
||||||
|
if (pEntry)
|
||||||
|
{
|
||||||
|
if (rkRes.Name.EndsWith("NODEPEND"))
|
||||||
|
rOut.push_back(rkRes.ID);
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mScanIDs.clear();
|
||||||
|
mAddingScans = false;
|
||||||
|
|
||||||
|
if (rkRes.Type == "MLVL")
|
||||||
|
{
|
||||||
|
CResourceEntry *pWorldEntry = gpResourceStore->FindEntry(rkRes.ID);
|
||||||
|
ASSERT(pWorldEntry);
|
||||||
|
mpWorld = (CWorld*) pWorldEntry->Load();
|
||||||
|
ASSERT(mpWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
EvaluateDependencies(pEntry, rOut);
|
||||||
|
|
||||||
|
mAddingScans = true;
|
||||||
|
for (auto Iter = mScanIDs.begin(); Iter != mScanIDs.end(); Iter++)
|
||||||
|
AddDependency(pEntry, *Iter, rOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
if (pCurEntry->ResourceType() == eDependencyGroup) return;
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(rkID);
|
||||||
|
EResType Type = (pEntry ? pEntry->ResourceType() : eResource);
|
||||||
|
|
||||||
|
// Defer scans to the end of the list. This is to accomodate the way the game loads SCANs; they are
|
||||||
|
// loaded separately from everything else after the area itself is done loading.
|
||||||
|
if (Type == eScan && !mAddingScans)
|
||||||
|
{
|
||||||
|
mScanIDs.push_back(rkID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure entry exists + is valid
|
||||||
|
if (pEntry && Type != eMidi && Type != eAudioGroupSet && Type != eWorld && (Type != eArea || pCurEntry->ResourceType() == eWorld))
|
||||||
|
{
|
||||||
|
if ( ( mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) == mAreaUsedAssets.end()) ||
|
||||||
|
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) == mPackageUsedAssets.end()) )
|
||||||
|
EvaluateDependencies(pEntry, rOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvaluateDependencies(CResourceEntry *pEntry, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
// Toggle duplicates
|
||||||
|
if (pEntry->ResourceType() == eArea && mEnableDuplicates)
|
||||||
|
{
|
||||||
|
mAreaUsedAssets.clear();
|
||||||
|
|
||||||
|
for (u32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
|
||||||
|
{
|
||||||
|
if (mpWorld->AreaResourceID(iArea) == pEntry->ID())
|
||||||
|
{
|
||||||
|
mCurrentAreaHasDuplicates = mpWorld->DoesAreaAllowPakDuplicates(iArea);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add dependencies
|
||||||
|
CDependencyTree *pTree = pEntry->Dependencies();
|
||||||
|
mPackageUsedAssets.insert(pTree->ID());
|
||||||
|
mAreaUsedAssets.insert(pTree->ID());
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < pTree->NumDependencies(); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(pEntry, ID, rOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add area script dependencies
|
||||||
|
if (pEntry->ResourceType() == eArea)
|
||||||
|
{
|
||||||
|
CAreaDependencyTree *pAreaTree = static_cast<CAreaDependencyTree*>(pTree);
|
||||||
|
|
||||||
|
for (u32 iInst = 0; iInst < pAreaTree->NumScriptInstances(); iInst++)
|
||||||
|
{
|
||||||
|
CScriptInstanceDependencyTree *pInstTree = pAreaTree->ScriptInstanceByIndex(iInst);
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < pInstTree->NumDependencies(); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pInstTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(pEntry, ID, rOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rOut.push_back(pTree->ID());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************ CAreaDependencyListBuilder ************
|
||||||
|
class CAreaDependencyListBuilder
|
||||||
|
{
|
||||||
|
CResourceEntry *mpAreaEntry;
|
||||||
|
std::set<CAssetID> mBaseUsedAssets;
|
||||||
|
std::set<CAssetID> mLayerUsedAssets;
|
||||||
|
bool mIsPlayerActor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAreaDependencyListBuilder(CResourceEntry *pAreaEntry)
|
||||||
|
: mpAreaEntry(pAreaEntry) {}
|
||||||
|
|
||||||
|
virtual void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut)
|
||||||
|
{
|
||||||
|
ASSERT(mpAreaEntry->ResourceType() == eArea);
|
||||||
|
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
|
||||||
|
|
||||||
|
// Fill area base used assets set (don't actually add to list yet)
|
||||||
|
for (u32 iDep = 0; iDep < pTree->NumDependencies(); iDep++)
|
||||||
|
mBaseUsedAssets.insert(pTree->DependencyByIndex(iDep));
|
||||||
|
|
||||||
|
// Get dependencies of each layer
|
||||||
|
for (u32 iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
|
||||||
|
{
|
||||||
|
mLayerUsedAssets.clear();
|
||||||
|
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
||||||
|
|
||||||
|
bool IsLastLayer = (iLyr == pTree->NumScriptLayers() - 1);
|
||||||
|
u32 StartIndex = pTree->ScriptLayerOffset(iLyr);
|
||||||
|
u32 EndIndex = (IsLastLayer ? pTree->NumScriptInstances() : pTree->ScriptLayerOffset(iLyr + 1));
|
||||||
|
|
||||||
|
for (u32 iInst = StartIndex; iInst < EndIndex; iInst++)
|
||||||
|
{
|
||||||
|
CScriptInstanceDependencyTree *pInstTree = pTree->ScriptInstanceByIndex(iInst);
|
||||||
|
mIsPlayerActor = (pInstTree->ObjectType() == 0x4C);
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < pInstTree->NumDependencies(); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pInstTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(mpAreaEntry, ID, rAssetsOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add base dependencies
|
||||||
|
mBaseUsedAssets.clear();
|
||||||
|
mLayerUsedAssets.clear();
|
||||||
|
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < pTree->NumDependencies(); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(mpAreaEntry, ID, rAssetsOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
if (pCurEntry->ResourceType() == eDependencyGroup) return;
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(rkID);
|
||||||
|
EResType Type = (pEntry ? pEntry->ResourceType() : eResource);
|
||||||
|
|
||||||
|
// Make sure entry exists + is valid
|
||||||
|
if (pEntry && Type != eMidi && Type != eAudioGroupSet && Type != eScan && Type != eWorld && Type != eArea)
|
||||||
|
{
|
||||||
|
if ( mBaseUsedAssets.find(rkID) == mBaseUsedAssets.end() && mLayerUsedAssets.find(rkID) == mLayerUsedAssets.end())
|
||||||
|
{
|
||||||
|
if (mIsPlayerActor && pEntry->ResourceType() == eAnimSet)
|
||||||
|
EvaluatePlayerActorAnimSet(pEntry, rOut);
|
||||||
|
else
|
||||||
|
EvaluateDependencies(pEntry, rOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvaluateDependencies(CResourceEntry *pEntry, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
CDependencyTree *pTree = pEntry->Dependencies();
|
||||||
|
mLayerUsedAssets.insert(pTree->ID());
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < pTree->NumDependencies(); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(pEntry, ID, rOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
rOut.push_back(pTree->ID());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvaluatePlayerActorAnimSet(CResourceEntry *pEntry, std::list<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
// For PlayerActor animsets we want to include only the empty suit (char 5) in the dependency list. This is to
|
||||||
|
// accomodate the dynamic loading the game does for PlayerActors to avoid having assets for suits the player
|
||||||
|
// doesn't have in memory. We want common assets (animations, etc) in the list but not per-character assets.
|
||||||
|
ASSERT(pEntry->ResourceType() == eAnimSet);
|
||||||
|
CAnimSetDependencyTree *pTree = static_cast<CAnimSetDependencyTree*>(pEntry->Dependencies());
|
||||||
|
mLayerUsedAssets.insert(pTree->ID());
|
||||||
|
|
||||||
|
// Add empty suit dependencies
|
||||||
|
ASSERT(pTree->NumCharacters() >= 7);
|
||||||
|
u32 StartIdx = pTree->CharacterOffset(5);
|
||||||
|
u32 EndIdx = pTree->CharacterOffset(6);
|
||||||
|
|
||||||
|
for (u32 iDep = StartIdx; iDep < EndIdx; iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(pEntry, ID, rOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add common dependencies
|
||||||
|
for (u32 iDep = 0; iDep < pTree->CharacterOffset(0); iDep++)
|
||||||
|
{
|
||||||
|
CAssetID ID = pTree->DependencyByIndex(iDep);
|
||||||
|
AddDependency(pEntry, ID, rOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
rOut.push_back(pTree->ID());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEPENDENCYLISTBUILDERS
|
||||||
|
|
|
@ -36,14 +36,11 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
|
||||||
// Base dependencies
|
// Base dependencies
|
||||||
CAreaDependencyTree *pTree = new CAreaDependencyTree(ID());
|
CAreaDependencyTree *pTree = new CAreaDependencyTree(ID());
|
||||||
|
|
||||||
for (u32 iMat = 0; iMat < mpMaterialSet->NumMaterials(); iMat++)
|
std::set<CAssetID> MatTextures;
|
||||||
{
|
mpMaterialSet->GetUsedTextureIDs(MatTextures);
|
||||||
CMaterial *pMat = mpMaterialSet->MaterialByIndex(iMat);
|
|
||||||
pTree->AddDependency(pMat->IndTexture());
|
|
||||||
|
|
||||||
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
for (auto Iter = MatTextures.begin(); Iter != MatTextures.end(); Iter++)
|
||||||
pTree->AddDependency(pMat->Pass(iPass)->Texture());
|
pTree->AddDependency(*Iter);
|
||||||
}
|
|
||||||
|
|
||||||
pTree->AddDependency(mPathID);
|
pTree->AddDependency(mPathID);
|
||||||
pTree->AddDependency(mPortalAreaID);
|
pTree->AddDependency(mPortalAreaID);
|
||||||
|
|
|
@ -58,12 +58,23 @@ public:
|
||||||
CDependencyTree* BuildDependencyTree() const
|
CDependencyTree* BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CAnimSetDependencyTree *pTree = new CAnimSetDependencyTree(ID());
|
CAnimSetDependencyTree *pTree = new CAnimSetDependencyTree(ID());
|
||||||
|
std::set<CAssetID> BaseUsedSet;
|
||||||
|
|
||||||
|
// Base dependencies
|
||||||
for (u32 iAnim = 0; iAnim < mAnims.size(); iAnim++)
|
for (u32 iAnim = 0; iAnim < mAnims.size(); iAnim++)
|
||||||
pTree->AddDependency(mAnims[iAnim].pAnim);
|
{
|
||||||
|
CAnimation *pAnim = mAnims[iAnim].pAnim;
|
||||||
|
|
||||||
|
if (pAnim)
|
||||||
|
{
|
||||||
|
pTree->AddDependency(mAnims[iAnim].pAnim);
|
||||||
|
BaseUsedSet.insert(pAnim->ID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Character dependencies
|
||||||
for (u32 iNode = 0; iNode < mCharacters.size(); iNode++)
|
for (u32 iNode = 0; iNode < mCharacters.size(); iNode++)
|
||||||
pTree->AddCharacter(&mCharacters[iNode]);
|
pTree->AddCharacter(&mCharacters[iNode], BaseUsedSet);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,21 @@ public:
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetUsedTextureIDs(std::set<CAssetID>& rOut)
|
||||||
|
{
|
||||||
|
for (u32 iMat = 0; iMat < mMaterials.size(); iMat++)
|
||||||
|
{
|
||||||
|
CMaterial *pMat = mMaterials[iMat];
|
||||||
|
if (pMat->IndTexture()) rOut.insert(pMat->IndTexture()->ID());
|
||||||
|
|
||||||
|
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
|
{
|
||||||
|
CTexture *pTex = pMat->Pass(iPass)->Texture();
|
||||||
|
if (pTex) rOut.insert(pTex->ID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CMATERIALSET_H
|
#endif // CMATERIALSET_H
|
||||||
|
|
|
@ -24,16 +24,16 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EGame mVersion;
|
EGame mVersion;
|
||||||
TResPtr<CResource> mpFrame;
|
CAssetID mFrameID;
|
||||||
TResPtr<CStringTable> mpStringTable;
|
TResPtr<CStringTable> mpStringTable;
|
||||||
bool mIsSlow;
|
bool mIsSlow;
|
||||||
bool mIsImportant;
|
bool mIsImportant;
|
||||||
ELogbookCategory mCategory;
|
ELogbookCategory mCategory;
|
||||||
|
CAssetID mScanImageTextures[4];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CScan(CResourceEntry *pEntry = 0)
|
CScan(CResourceEntry *pEntry = 0)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mpFrame(nullptr)
|
|
||||||
, mpStringTable(nullptr)
|
, mpStringTable(nullptr)
|
||||||
, mIsSlow(false)
|
, mIsSlow(false)
|
||||||
, mIsImportant(false)
|
, mIsImportant(false)
|
||||||
|
@ -46,8 +46,12 @@ public:
|
||||||
Log::Warning("CScan::BuildDependencyTree not handling Echoes/Corruption dependencies");
|
Log::Warning("CScan::BuildDependencyTree not handling Echoes/Corruption dependencies");
|
||||||
|
|
||||||
CDependencyTree *pTree = new CDependencyTree(ID());
|
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||||
pTree->AddDependency(mpFrame);
|
pTree->AddDependency(mFrameID);
|
||||||
pTree->AddDependency(mpStringTable);
|
pTree->AddDependency(mpStringTable);
|
||||||
|
|
||||||
|
for (u32 iImg = 0; iImg < 4; iImg++)
|
||||||
|
pTree->AddDependency(mScanImageTextures[iImg]);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
CDependencyTree* BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
// The only dependencies STRGs have is they can reference FONTs with the &font=; formatting tag
|
// STRGs can reference FONTs with the &font=; formatting tag and TXTRs with the &image=; tag
|
||||||
CDependencyTree *pTree = new CDependencyTree(ID());
|
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||||
EIDLength IDLength = (Game() <= eEchoes ? e32Bit : e64Bit);
|
EIDLength IDLength = (Game() <= eEchoes ? e32Bit : e64Bit);
|
||||||
|
|
||||||
|
@ -54,14 +54,69 @@ public:
|
||||||
|
|
||||||
for (u32 iStr = 0; iStr < rkTable.Strings.size(); iStr++)
|
for (u32 iStr = 0; iStr < rkTable.Strings.size(); iStr++)
|
||||||
{
|
{
|
||||||
static const TWideString skTag = L"&font=";
|
|
||||||
const TWideString& rkStr = rkTable.Strings[iStr];
|
const TWideString& rkStr = rkTable.Strings[iStr];
|
||||||
|
|
||||||
for (u32 FontIdx = rkStr.IndexOfPhrase(*skTag); FontIdx != -1; FontIdx = rkStr.IndexOfPhrase(*skTag, FontIdx + 1))
|
for (u32 TagIdx = rkStr.IndexOf(L'&'); TagIdx != -1; TagIdx = rkStr.IndexOf(L'&', TagIdx + 1))
|
||||||
{
|
{
|
||||||
u32 IDStart = FontIdx + skTag.Size();
|
// Check for double ampersand (escape character in DKCR, not sure about other games)
|
||||||
TWideString StrFontID = rkStr.SubString(IDStart, IDLength * 2);
|
if (rkStr.At(TagIdx + 1) == L'&')
|
||||||
pTree->AddDependency( CAssetID::FromString(StrFontID) );
|
{
|
||||||
|
TagIdx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tag name and parameters
|
||||||
|
u32 NameEnd = rkStr.IndexOf(L'=', TagIdx);
|
||||||
|
u32 TagEnd = rkStr.IndexOf(L';', TagIdx);
|
||||||
|
if (NameEnd == -1 || TagEnd == -1) continue;
|
||||||
|
|
||||||
|
TWideString TagName = rkStr.SubString(TagIdx + 1, NameEnd - TagIdx - 1);
|
||||||
|
TWideString ParamString = rkStr.SubString(NameEnd + 1, TagEnd - NameEnd - 1);
|
||||||
|
|
||||||
|
// Font
|
||||||
|
if (TagName == L"font")
|
||||||
|
{
|
||||||
|
ASSERT(ParamString.Size() == IDLength * 2);
|
||||||
|
pTree->AddDependency( CAssetID::FromString(ParamString) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image
|
||||||
|
else if (TagName == L"image")
|
||||||
|
{
|
||||||
|
// Determine which params are textures based on image type
|
||||||
|
TWideStringList Params = ParamString.Split(L",");
|
||||||
|
TWideString ImageType = Params.front();
|
||||||
|
u32 TexturesStart = -1;
|
||||||
|
|
||||||
|
if (ImageType == L"A")
|
||||||
|
TexturesStart = 2;
|
||||||
|
|
||||||
|
else if (ImageType == L"SI")
|
||||||
|
TexturesStart = 3;
|
||||||
|
|
||||||
|
else if (ImageType == L"SA")
|
||||||
|
TexturesStart = 4;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log::Error("Unrecognized image type: " + ImageType.ToUTF8());
|
||||||
|
DEBUG_BREAK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load texture IDs
|
||||||
|
TWideStringList::iterator Iter = Params.begin();
|
||||||
|
|
||||||
|
for (u32 iParam = 0; iParam < Params.size(); iParam++, Iter++)
|
||||||
|
{
|
||||||
|
if (iParam >= TexturesStart)
|
||||||
|
{
|
||||||
|
TWideString Param = *Iter;
|
||||||
|
ASSERT(Param.Size() == IDLength * 2);
|
||||||
|
pTree->AddDependency( CAssetID::FromString(Param) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ void Serialize(IArchive& rArc, CWorld::SArea& rArea)
|
||||||
<< SERIAL("BoundingBox", rArea.AetherBox)
|
<< SERIAL("BoundingBox", rArea.AetherBox)
|
||||||
<< SERIAL("AreaMREA", rArea.AreaResID)
|
<< SERIAL("AreaMREA", rArea.AreaResID)
|
||||||
<< SERIAL_HEX("AreaID", rArea.AreaID)
|
<< SERIAL_HEX("AreaID", rArea.AreaID)
|
||||||
|
<< SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates)
|
||||||
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
|
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
|
||||||
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
|
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
|
||||||
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
|
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
|
||||||
|
|
|
@ -11,6 +11,7 @@ class CWorld : public CResource
|
||||||
{
|
{
|
||||||
DECLARE_RESOURCE_TYPE(eWorld)
|
DECLARE_RESOURCE_TYPE(eWorld)
|
||||||
friend class CWorldLoader;
|
friend class CWorldLoader;
|
||||||
|
friend class CWorldCooker;
|
||||||
|
|
||||||
// Instances of CResource pointers are placeholders for unimplemented resource types (eg CMapWorld)
|
// Instances of CResource pointers are placeholders for unimplemented resource types (eg CMapWorld)
|
||||||
EGame mWorldVersion;
|
EGame mWorldVersion;
|
||||||
|
@ -48,6 +49,7 @@ class CWorld : public CResource
|
||||||
CAABox AetherBox;
|
CAABox AetherBox;
|
||||||
CAssetID AreaResID; // 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;
|
u64 AreaID;
|
||||||
|
bool AllowPakDuplicates;
|
||||||
|
|
||||||
std::vector<u16> AttachedAreaIDs;
|
std::vector<u16> AttachedAreaIDs;
|
||||||
std::vector<CAssetID> Dependencies;
|
std::vector<CAssetID> Dependencies;
|
||||||
|
@ -103,11 +105,14 @@ public:
|
||||||
inline CResource* MapWorld() const { return mpMapWorld; }
|
inline CResource* MapWorld() const { return mpMapWorld; }
|
||||||
|
|
||||||
inline u32 NumAreas() const { return mAreas.size(); }
|
inline u32 NumAreas() const { return mAreas.size(); }
|
||||||
inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID.ToLongLong(); }
|
inline CAssetID AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID; }
|
||||||
inline u32 AreaAttachedCount(u32 AreaIndex) const { return mAreas[AreaIndex].AttachedAreaIDs.size(); }
|
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 u32 AreaAttachedID(u32 AreaIndex, u32 AttachedIndex) const { return mAreas[AreaIndex].AttachedAreaIDs[AttachedIndex]; }
|
||||||
inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; }
|
inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; }
|
||||||
inline CStringTable* AreaName(u32 AreaIndex) const { return mAreas[AreaIndex].pAreaName; }
|
inline CStringTable* AreaName(u32 AreaIndex) const { return mAreas[AreaIndex].pAreaName; }
|
||||||
|
inline bool DoesAreaAllowPakDuplicates(u32 AreaIndex) const { return mAreas[AreaIndex].AllowPakDuplicates; }
|
||||||
|
|
||||||
|
inline void SetAreaAllowsPakDuplicates(u32 AreaIndex, bool Allow) { mAreas[AreaIndex].AllowPakDuplicates = Allow; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CWORLD_H
|
#endif // CWORLD_H
|
||||||
|
|
|
@ -31,6 +31,4 @@ void CPoiToWorldCooker::WriteEGMC(CPoiToWorld *pPoiToWorld, IOutputStream& rOut)
|
||||||
rOut.WriteLong(Mappings[iMap].MeshID);
|
rOut.WriteLong(Mappings[iMap].MeshID);
|
||||||
rOut.WriteLong(Mappings[iMap].PoiID);
|
rOut.WriteLong(Mappings[iMap].PoiID);
|
||||||
}
|
}
|
||||||
|
|
||||||
rOut.WriteToBoundary(32, -1);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,162 @@
|
||||||
#include "CWorldCooker.h"
|
#include "CWorldCooker.h"
|
||||||
|
#include "Core/GameProject/DependencyListBuilders.h"
|
||||||
|
|
||||||
CWorldCooker::CWorldCooker()
|
CWorldCooker::CWorldCooker()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ************ STATIC ************
|
||||||
|
bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||||
|
{
|
||||||
|
ASSERT(rMLVL.IsValid());
|
||||||
|
|
||||||
|
// MLVL Header
|
||||||
|
rMLVL.WriteLong(0xDEAFBABE);
|
||||||
|
rMLVL.WriteLong( GetMLVLVersion(pWorld->Game()) );
|
||||||
|
|
||||||
|
CAssetID WorldNameID = pWorld->mpWorldName ? pWorld->mpWorldName->ID() : CAssetID::skInvalidID32;
|
||||||
|
CAssetID SaveWorldID = pWorld->mpSaveWorld ? pWorld->mpSaveWorld->ID() : CAssetID::skInvalidID32;
|
||||||
|
CAssetID DefaultSkyID = pWorld->mpDefaultSkybox ? pWorld->mpDefaultSkybox->ID() : CAssetID::skInvalidID32;
|
||||||
|
|
||||||
|
WorldNameID.Write(rMLVL);
|
||||||
|
SaveWorldID.Write(rMLVL);
|
||||||
|
DefaultSkyID.Write(rMLVL);
|
||||||
|
|
||||||
|
// Memory Relays
|
||||||
|
rMLVL.WriteLong( pWorld->mMemoryRelays.size() );
|
||||||
|
|
||||||
|
for (u32 iMem = 0; iMem < pWorld->mMemoryRelays.size(); iMem++)
|
||||||
|
{
|
||||||
|
CWorld::SMemoryRelay& rRelay = pWorld->mMemoryRelays[iMem];
|
||||||
|
rMLVL.WriteLong(rRelay.InstanceID);
|
||||||
|
rMLVL.WriteLong(rRelay.TargetID);
|
||||||
|
rMLVL.WriteShort(rRelay.Message);
|
||||||
|
rMLVL.WriteByte(rRelay.Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Areas
|
||||||
|
rMLVL.WriteLong(pWorld->mAreas.size());
|
||||||
|
rMLVL.WriteLong(1); // Unknown
|
||||||
|
|
||||||
|
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
|
||||||
|
{
|
||||||
|
// Area Header
|
||||||
|
CWorld::SArea& rArea = pWorld->mAreas[iArea];
|
||||||
|
CResourceEntry *pAreaEntry = gpResourceStore->FindEntry(rArea.AreaResID);
|
||||||
|
ASSERT(pAreaEntry && pAreaEntry->ResourceType() == eArea);
|
||||||
|
|
||||||
|
CAssetID AreaNameID = rArea.pAreaName ? rArea.pAreaName->ID() : CAssetID::skInvalidID32;
|
||||||
|
AreaNameID.Write(rMLVL);
|
||||||
|
rArea.Transform.Write(rMLVL);
|
||||||
|
rArea.AetherBox.Write(rMLVL);
|
||||||
|
rArea.AreaResID.Write(rMLVL);
|
||||||
|
rMLVL.WriteLong( (u32) rArea.AreaID );
|
||||||
|
|
||||||
|
// Attached Areas
|
||||||
|
rMLVL.WriteLong( rArea.AttachedAreaIDs.size() );
|
||||||
|
|
||||||
|
for (u32 iAttach = 0; iAttach < rArea.AttachedAreaIDs.size(); iAttach++)
|
||||||
|
rMLVL.WriteShort(rArea.AttachedAreaIDs[iAttach]);
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
std::list<CAssetID> Dependencies;
|
||||||
|
std::list<u32> LayerDependsOffsets;
|
||||||
|
CAreaDependencyListBuilder Builder(pAreaEntry);
|
||||||
|
Builder.BuildDependencyList(Dependencies, LayerDependsOffsets);
|
||||||
|
|
||||||
|
rMLVL.WriteLong(0);
|
||||||
|
rMLVL.WriteLong( Dependencies.size() );
|
||||||
|
|
||||||
|
for (auto Iter = Dependencies.begin(); Iter != Dependencies.end(); Iter++)
|
||||||
|
{
|
||||||
|
CAssetID ID = *Iter;
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
|
ID.Write(rMLVL);
|
||||||
|
pEntry->CookedExtension().Write(rMLVL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rMLVL.WriteLong(LayerDependsOffsets.size());
|
||||||
|
|
||||||
|
for (auto Iter = LayerDependsOffsets.begin(); Iter != LayerDependsOffsets.end(); Iter++)
|
||||||
|
rMLVL.WriteLong(*Iter);
|
||||||
|
|
||||||
|
// Docks
|
||||||
|
rMLVL.WriteLong( rArea.Docks.size() );
|
||||||
|
|
||||||
|
for (u32 iDock = 0; iDock < rArea.Docks.size(); iDock++)
|
||||||
|
{
|
||||||
|
CWorld::SArea::SDock& rDock = rArea.Docks[iDock];
|
||||||
|
rMLVL.WriteLong( rDock.ConnectingDocks.size() );
|
||||||
|
|
||||||
|
for (u32 iCon = 0; iCon < rDock.ConnectingDocks.size(); iCon++)
|
||||||
|
{
|
||||||
|
CWorld::SArea::SDock::SConnectingDock& rConDock = rDock.ConnectingDocks[iCon];
|
||||||
|
rMLVL.WriteLong(rConDock.AreaIndex);
|
||||||
|
rMLVL.WriteLong(rConDock.DockIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
rMLVL.WriteLong( rDock.DockCoordinates.size() );
|
||||||
|
|
||||||
|
for (u32 iCoord = 0; iCoord < rDock.DockCoordinates.size(); iCoord++)
|
||||||
|
rDock.DockCoordinates[iCoord].Write(rMLVL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAssetID MapWorldID = pWorld->mpMapWorld ? pWorld->mpMapWorld->ID() : CAssetID::skInvalidID32;
|
||||||
|
MapWorldID.Write(rMLVL);
|
||||||
|
rMLVL.WriteByte(0);
|
||||||
|
rMLVL.WriteLong(0);
|
||||||
|
|
||||||
|
// Audio Groups
|
||||||
|
rMLVL.WriteLong(pWorld->mAudioGrps.size());
|
||||||
|
|
||||||
|
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
|
||||||
|
{
|
||||||
|
CWorld::SAudioGrp& rAudioGroup = pWorld->mAudioGrps[iGrp];
|
||||||
|
rMLVL.WriteLong(rAudioGroup.Unknown);
|
||||||
|
rAudioGroup.ResID.Write(rMLVL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rMLVL.WriteByte(0);
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
rMLVL.WriteLong(pWorld->mAreas.size());
|
||||||
|
std::vector<TString> LayerNames;
|
||||||
|
std::vector<u32> LayerNameOffsets;
|
||||||
|
|
||||||
|
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
|
||||||
|
{
|
||||||
|
CWorld::SArea& rArea = pWorld->mAreas[iArea];
|
||||||
|
LayerNameOffsets.push_back(LayerNames.size());
|
||||||
|
rMLVL.WriteLong(rArea.Layers.size());
|
||||||
|
|
||||||
|
u64 LayerActiveFlags = -1;
|
||||||
|
|
||||||
|
for (u32 iLyr = 0; iLyr < rArea.Layers.size(); iLyr++)
|
||||||
|
{
|
||||||
|
CWorld::SArea::SLayer& rLayer = rArea.Layers[iLyr];
|
||||||
|
if (!rLayer.EnabledByDefault)
|
||||||
|
LayerActiveFlags &= ~(1 << iLyr);
|
||||||
|
|
||||||
|
LayerNames.push_back(rLayer.LayerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
rMLVL.WriteLongLong(LayerActiveFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rMLVL.WriteLong(LayerNames.size());
|
||||||
|
|
||||||
|
for (u32 iLyr = 0; iLyr < LayerNames.size(); iLyr++)
|
||||||
|
rMLVL.WriteString(LayerNames[iLyr].ToStdString());
|
||||||
|
|
||||||
|
rMLVL.WriteLong(LayerNameOffsets.size());
|
||||||
|
|
||||||
|
for (u32 iOff = 0; iOff < LayerNameOffsets.size(); iOff++)
|
||||||
|
rMLVL.WriteLong(LayerNameOffsets[iOff]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
u32 CWorldCooker::GetMLVLVersion(EGame Version)
|
u32 CWorldCooker::GetMLVLVersion(EGame Version)
|
||||||
{
|
{
|
||||||
switch (Version)
|
switch (Version)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CWORLDCOOKER_H
|
#ifndef CWORLDCOOKER_H
|
||||||
#define CWORLDCOOKER_H
|
#define CWORLDCOOKER_H
|
||||||
|
|
||||||
|
#include "Core/Resource/CWorld.h"
|
||||||
#include "Core/Resource/EGame.h"
|
#include "Core/Resource/EGame.h"
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ class CWorldCooker
|
||||||
{
|
{
|
||||||
CWorldCooker();
|
CWorldCooker();
|
||||||
public:
|
public:
|
||||||
|
static bool CookMLVL(CWorld *pWorld, IOutputStream& rOut);
|
||||||
static u32 GetMLVLVersion(EGame Version);
|
static u32 GetMLVLVersion(EGame Version);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -681,6 +681,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||||
Loader.ReadSCLYPrime();
|
Loader.ReadSCLYPrime();
|
||||||
Loader.ReadCollision();
|
Loader.ReadCollision();
|
||||||
Loader.ReadLightsPrime();
|
Loader.ReadLightsPrime();
|
||||||
|
Loader.ReadPATH();
|
||||||
break;
|
break;
|
||||||
case eEchoesDemo:
|
case eEchoesDemo:
|
||||||
Loader.ReadHeaderEchoes();
|
Loader.ReadHeaderEchoes();
|
||||||
|
@ -688,6 +689,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||||
Loader.ReadSCLYPrime();
|
Loader.ReadSCLYPrime();
|
||||||
Loader.ReadCollision();
|
Loader.ReadCollision();
|
||||||
Loader.ReadLightsPrime();
|
Loader.ReadLightsPrime();
|
||||||
|
Loader.ReadPATH();
|
||||||
|
Loader.ReadPTLA();
|
||||||
Loader.ReadEGMC();
|
Loader.ReadEGMC();
|
||||||
break;
|
break;
|
||||||
case eEchoes:
|
case eEchoes:
|
||||||
|
@ -696,6 +699,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||||
Loader.ReadSCLYEchoes();
|
Loader.ReadSCLYEchoes();
|
||||||
Loader.ReadCollision();
|
Loader.ReadCollision();
|
||||||
Loader.ReadLightsPrime();
|
Loader.ReadLightsPrime();
|
||||||
|
Loader.ReadPATH();
|
||||||
|
Loader.ReadPTLA();
|
||||||
Loader.ReadEGMC();
|
Loader.ReadEGMC();
|
||||||
break;
|
break;
|
||||||
case eCorruptionProto:
|
case eCorruptionProto:
|
||||||
|
@ -704,6 +709,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||||
Loader.ReadSCLYEchoes();
|
Loader.ReadSCLYEchoes();
|
||||||
Loader.ReadCollision();
|
Loader.ReadCollision();
|
||||||
Loader.ReadLightsCorruption();
|
Loader.ReadLightsCorruption();
|
||||||
|
Loader.ReadPATH();
|
||||||
|
Loader.ReadPTLA();
|
||||||
Loader.ReadEGMC();
|
Loader.ReadEGMC();
|
||||||
break;
|
break;
|
||||||
case eCorruption:
|
case eCorruption:
|
||||||
|
@ -715,6 +722,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||||
if (Loader.mVersion == eCorruption)
|
if (Loader.mVersion == eCorruption)
|
||||||
{
|
{
|
||||||
Loader.ReadLightsCorruption();
|
Loader.ReadLightsCorruption();
|
||||||
|
Loader.ReadPATH();
|
||||||
|
Loader.ReadPTLA();
|
||||||
Loader.ReadEGMC();
|
Loader.ReadEGMC();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,8 +5,8 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
|
||||||
{
|
{
|
||||||
// Only difference between versions is asset ID length. Just check for EOF with 32-bit ID length.
|
// Only difference between versions is asset ID length. Just check for EOF with 32-bit ID length.
|
||||||
u32 Start = rDGRP.Tell();
|
u32 Start = rDGRP.Tell();
|
||||||
rDGRP.Seek(DepCount * 4, SEEK_CUR);
|
rDGRP.Seek(DepCount * 8, SEEK_CUR);
|
||||||
u32 Remaining = rDGRP.Size() - Start;
|
u32 Remaining = rDGRP.Size() - rDGRP.Tell();
|
||||||
|
|
||||||
EGame Game = ePrimeDemo;
|
EGame Game = ePrimeDemo;
|
||||||
|
|
||||||
|
@ -14,7 +14,9 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
|
||||||
{
|
{
|
||||||
for (u32 iRem = 0; iRem < Remaining; iRem++)
|
for (u32 iRem = 0; iRem < Remaining; iRem++)
|
||||||
{
|
{
|
||||||
if (rDGRP.ReadByte() != 0xFF)
|
u8 Byte = rDGRP.ReadByte();
|
||||||
|
|
||||||
|
if (Byte != 0xFF)
|
||||||
{
|
{
|
||||||
Game = eCorruptionProto;
|
Game = eCorruptionProto;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -120,7 +120,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
|
||||||
if (pMat->mOptions & CMaterial::eIndStage)
|
if (pMat->mOptions & CMaterial::eIndStage)
|
||||||
{
|
{
|
||||||
u32 IndTexIndex = mpFile->ReadLong();
|
u32 IndTexIndex = mpFile->ReadLong();
|
||||||
pMat->mpIndirectTexture = mTextures[IndTexIndex];
|
pMat->mpIndirectTexture = mTextures[TextureIndices[IndTexIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color channels
|
// Color channels
|
||||||
|
@ -162,7 +162,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
|
||||||
|
|
||||||
u8 TexSel = mpFile->ReadByte();
|
u8 TexSel = mpFile->ReadByte();
|
||||||
|
|
||||||
if ((TexSel == 0xFF) || (TexSel >= mTextures.size()))
|
if ((TexSel == 0xFF) || (TexSel >= TextureIndices.size()))
|
||||||
pPass->mpTexture = nullptr;
|
pPass->mpTexture = nullptr;
|
||||||
else
|
else
|
||||||
pPass->mpTexture = mTextures[TextureIndices[TexSel]];
|
pPass->mpTexture = mTextures[TextureIndices[TexSel]];
|
||||||
|
|
|
@ -9,11 +9,18 @@ CScanLoader::CScanLoader()
|
||||||
CScan* CScanLoader::LoadScanMP1(IInputStream& rSCAN)
|
CScan* CScanLoader::LoadScanMP1(IInputStream& rSCAN)
|
||||||
{
|
{
|
||||||
// Basic support at the moment - don't read animation/scan image data
|
// Basic support at the moment - don't read animation/scan image data
|
||||||
rSCAN.Seek(0x4, SEEK_CUR); // Skip FRME ID
|
mpScan->mFrameID = CAssetID(rSCAN, e32Bit);
|
||||||
mpScan->mpStringTable = gpResourceStore->LoadResource(rSCAN.ReadLong(), "STRG");
|
mpScan->mpStringTable = gpResourceStore->LoadResource(rSCAN.ReadLong(), "STRG");
|
||||||
mpScan->mIsSlow = (rSCAN.ReadLong() != 0);
|
mpScan->mIsSlow = (rSCAN.ReadLong() != 0);
|
||||||
mpScan->mCategory = (CScan::ELogbookCategory) rSCAN.ReadLong();
|
mpScan->mCategory = (CScan::ELogbookCategory) rSCAN.ReadLong();
|
||||||
mpScan->mIsImportant = (rSCAN.ReadByte() == 1);
|
mpScan->mIsImportant = (rSCAN.ReadByte() == 1);
|
||||||
|
|
||||||
|
for (u32 iImg = 0; iImg < 4; iImg++)
|
||||||
|
{
|
||||||
|
mpScan->mScanImageTextures[iImg] = CAssetID(rSCAN, e32Bit);
|
||||||
|
rSCAN.Seek(0x18, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
mpScan->mVersion = ePrime;
|
mpScan->mVersion = ePrime;
|
||||||
return mpScan;
|
return mpScan;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,24 +33,17 @@ CModel::~CModel()
|
||||||
CDependencyTree* CModel::BuildDependencyTree() const
|
CDependencyTree* CModel::BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree(ID());
|
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||||
|
std::set<CAssetID> TextureIDs;
|
||||||
|
|
||||||
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
|
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
|
||||||
{
|
{
|
||||||
CMaterialSet *pSet = mMaterialSets[iSet];
|
CMaterialSet *pSet = mMaterialSets[iSet];
|
||||||
|
pSet->GetUsedTextureIDs(TextureIDs);
|
||||||
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
|
||||||
{
|
|
||||||
CMaterial *pMat = pSet->MaterialByIndex(iMat);
|
|
||||||
pTree->AddDependency(pMat->IndTexture());
|
|
||||||
|
|
||||||
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
|
||||||
{
|
|
||||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
|
||||||
pTree->AddDependency(pPass->Texture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto Iter = TextureIDs.begin(); Iter != TextureIDs.end(); Iter++)
|
||||||
|
pTree->AddDependency(*Iter);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ CProjectOverviewDialog::CProjectOverviewDialog(QWidget *pParent)
|
||||||
connect(mpUI->LoadWorldButton, SIGNAL(clicked()), this, SLOT(LoadWorld()));
|
connect(mpUI->LoadWorldButton, SIGNAL(clicked()), this, SLOT(LoadWorld()));
|
||||||
connect(mpUI->LaunchEditorButton, SIGNAL(clicked()), this, SLOT(LaunchEditor()));
|
connect(mpUI->LaunchEditorButton, SIGNAL(clicked()), this, SLOT(LaunchEditor()));
|
||||||
connect(mpUI->ViewResourcesButton, SIGNAL(clicked()), this, SLOT(LaunchResourceBrowser()));
|
connect(mpUI->ViewResourcesButton, SIGNAL(clicked()), this, SLOT(LaunchResourceBrowser()));
|
||||||
|
connect(mpUI->CookPackageButton, SIGNAL(clicked()), this, SLOT(CookPackage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CProjectOverviewDialog::~CProjectOverviewDialog()
|
CProjectOverviewDialog::~CProjectOverviewDialog()
|
||||||
|
@ -44,6 +45,7 @@ void CProjectOverviewDialog::OpenProject()
|
||||||
mpProject = pNewProj;
|
mpProject = pNewProj;
|
||||||
mpProject->SetActive();
|
mpProject->SetActive();
|
||||||
SetupWorldsList();
|
SetupWorldsList();
|
||||||
|
SetupPackagesList();
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -113,6 +115,19 @@ void CProjectOverviewDialog::SetupWorldsList()
|
||||||
mpUI->LoadWorldButton->setEnabled(!mWorldEntries.isEmpty());
|
mpUI->LoadWorldButton->setEnabled(!mWorldEntries.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CProjectOverviewDialog::SetupPackagesList()
|
||||||
|
{
|
||||||
|
ASSERT(mpProject != nullptr && mpProject->IsActive());
|
||||||
|
mpUI->PackagesList->clear();
|
||||||
|
|
||||||
|
for (u32 iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++)
|
||||||
|
{
|
||||||
|
CPackage *pPackage = mpProject->PackageByIndex(iPkg);
|
||||||
|
ASSERT(pPackage != nullptr);
|
||||||
|
mpUI->PackagesList->addItem(TO_QSTRING(pPackage->Name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CProjectOverviewDialog::LoadWorld()
|
void CProjectOverviewDialog::LoadWorld()
|
||||||
{
|
{
|
||||||
// Find world
|
// Find world
|
||||||
|
@ -145,9 +160,6 @@ void CProjectOverviewDialog::LoadWorld()
|
||||||
|
|
||||||
void CProjectOverviewDialog::LaunchEditor()
|
void CProjectOverviewDialog::LaunchEditor()
|
||||||
{
|
{
|
||||||
CGameArea *pOldArea = mpWorldEditor->ActiveArea();
|
|
||||||
(void) pOldArea;
|
|
||||||
|
|
||||||
// Load area
|
// Load area
|
||||||
u32 AreaIdx = mpUI->AreaComboBox->currentIndex();
|
u32 AreaIdx = mpUI->AreaComboBox->currentIndex();
|
||||||
CResourceEntry *pAreaEntry = mAreaEntries[AreaIdx];
|
CResourceEntry *pAreaEntry = mAreaEntries[AreaIdx];
|
||||||
|
@ -172,3 +184,10 @@ void CProjectOverviewDialog::LaunchResourceBrowser()
|
||||||
CResourceBrowser Browser(this);
|
CResourceBrowser Browser(this);
|
||||||
Browser.exec();
|
Browser.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CProjectOverviewDialog::CookPackage()
|
||||||
|
{
|
||||||
|
u32 PackageIdx = mpUI->PackagesList->currentRow();
|
||||||
|
CPackage *pPackage = mpProject->PackageByIndex(PackageIdx);
|
||||||
|
pPackage->Cook();
|
||||||
|
}
|
||||||
|
|
|
@ -31,8 +31,10 @@ public slots:
|
||||||
void LoadWorld();
|
void LoadWorld();
|
||||||
void LaunchEditor();
|
void LaunchEditor();
|
||||||
void LaunchResourceBrowser();
|
void LaunchResourceBrowser();
|
||||||
|
void CookPackage();
|
||||||
|
|
||||||
void SetupWorldsList();
|
void SetupWorldsList();
|
||||||
|
void SetupPackagesList();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPROJECTOVERVIEWDIALOG_H
|
#endif // CPROJECTOVERVIEWDIALOG_H
|
||||||
|
|
|
@ -6,98 +6,129 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>268</width>
|
<width>492</width>
|
||||||
<height>367</height>
|
<height>445</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Dialog</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="OpenProjectButton">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Open Project</string>
|
<widget class="QPushButton" name="OpenProjectButton">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Open Project</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ExportGameButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export Game</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="ExportGameButton">
|
<widget class="QPushButton" name="ViewResourcesButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Export Game</string>
|
<string>View Resources</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="ViewResourcesButton">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>View Resources</string>
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
</property>
|
<item>
|
||||||
</widget>
|
<widget class="QGroupBox" name="WorldsGroupBox">
|
||||||
</item>
|
<property name="sizePolicy">
|
||||||
<item>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<widget class="QGroupBox" name="WorldsGroupBox">
|
<horstretch>2</horstretch>
|
||||||
<property name="sizePolicy">
|
<verstretch>0</verstretch>
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
</sizepolicy>
|
||||||
<horstretch>2</horstretch>
|
</property>
|
||||||
<verstretch>0</verstretch>
|
<property name="title">
|
||||||
</sizepolicy>
|
<string>Worlds</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<string>Worlds</string>
|
<item>
|
||||||
</property>
|
<widget class="QListWidget" name="WorldsList"/>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="WorldsList"/>
|
<widget class="QPushButton" name="LoadWorldButton">
|
||||||
</item>
|
<property name="enabled">
|
||||||
<item>
|
<bool>false</bool>
|
||||||
<widget class="QPushButton" name="LoadWorldButton">
|
</property>
|
||||||
<property name="enabled">
|
<property name="text">
|
||||||
<bool>false</bool>
|
<string>Load</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
</widget>
|
||||||
<string>Load</string>
|
</item>
|
||||||
</property>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item>
|
||||||
</widget>
|
<widget class="QGroupBox" name="AreasGroupBox">
|
||||||
</item>
|
<property name="sizePolicy">
|
||||||
<item>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<widget class="QGroupBox" name="AreasGroupBox">
|
<horstretch>3</horstretch>
|
||||||
<property name="sizePolicy">
|
<verstretch>0</verstretch>
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
</sizepolicy>
|
||||||
<horstretch>3</horstretch>
|
</property>
|
||||||
<verstretch>0</verstretch>
|
<property name="title">
|
||||||
</sizepolicy>
|
<string>Areas</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<string>Areas</string>
|
<item>
|
||||||
</property>
|
<widget class="QComboBox" name="AreaComboBox">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<property name="enabled">
|
||||||
<item>
|
<bool>false</bool>
|
||||||
<widget class="QComboBox" name="AreaComboBox">
|
</property>
|
||||||
<property name="enabled">
|
</widget>
|
||||||
<bool>false</bool>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
</widget>
|
<widget class="QPushButton" name="LaunchEditorButton">
|
||||||
</item>
|
<property name="enabled">
|
||||||
<item>
|
<bool>false</bool>
|
||||||
<widget class="QPushButton" name="LaunchEditorButton">
|
</property>
|
||||||
<property name="enabled">
|
<property name="text">
|
||||||
<bool>false</bool>
|
<string>Launch World Editor</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
</widget>
|
||||||
<string>Launch World Editor</string>
|
</item>
|
||||||
</property>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="PackagesGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Packages</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="PackagesList"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="CookPackageButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cook Package</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -144,14 +144,8 @@ void CStartWindow::FillAreaUI()
|
||||||
else
|
else
|
||||||
ui->AreaNameSTRGLineEdit->clear();
|
ui->AreaNameSTRGLineEdit->clear();
|
||||||
|
|
||||||
u64 MREA = mpWorld->AreaResourceID(mSelectedAreaIndex);
|
CAssetID MREA = mpWorld->AreaResourceID(mSelectedAreaIndex);
|
||||||
TString MREAStr;
|
ui->AreaMREALineEdit->setText(TO_QSTRING(MREA.ToString()) + QString(".MREA"));
|
||||||
if (MREA & 0xFFFFFFFF00000000)
|
|
||||||
MREAStr = TString::FromInt64(MREA, 16);
|
|
||||||
else
|
|
||||||
MREAStr = TString::FromInt32(MREA, 8);
|
|
||||||
|
|
||||||
ui->AreaMREALineEdit->setText(TO_QSTRING(MREAStr) + QString(".MREA"));
|
|
||||||
|
|
||||||
u32 NumAttachedAreas = mpWorld->AreaAttachedCount(mSelectedAreaIndex);
|
u32 NumAttachedAreas = mpWorld->AreaAttachedCount(mSelectedAreaIndex);
|
||||||
ui->AttachedAreasList->clear();
|
ui->AttachedAreasList->clear();
|
||||||
|
|
|
@ -75,7 +75,7 @@ void IOutputStream::WriteWideString(const std::wstring& rkVal, unsigned long Cou
|
||||||
WriteShort(0);
|
WriteShort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOutputStream::WriteToBoundary(unsigned long Boundary, char Fill)
|
void IOutputStream::WriteToBoundary(unsigned long Boundary, unsigned char Fill)
|
||||||
{
|
{
|
||||||
long Num = Boundary - (Tell() % Boundary);
|
long Num = Boundary - (Tell() % Boundary);
|
||||||
if (Num == Boundary) return;
|
if (Num == Boundary) return;
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
void WriteWideString(const std::wstring& rkVal);
|
void WriteWideString(const std::wstring& rkVal);
|
||||||
void WriteWideString(const std::wstring& rkVal, unsigned long Count, bool Terminate = false);
|
void WriteWideString(const std::wstring& rkVal, unsigned long Count, bool Terminate = false);
|
||||||
|
|
||||||
void WriteToBoundary(unsigned long Boundary, char Fill);
|
void WriteToBoundary(unsigned long Boundary, unsigned char Fill);
|
||||||
void SetEndianness(IOUtil::EEndianness Endianness);
|
void SetEndianness(IOUtil::EEndianness Endianness);
|
||||||
void SetDestString(const std::string& rkDest);
|
void SetDestString(const std::string& rkDest);
|
||||||
IOUtil::EEndianness GetEndianness() const;
|
IOUtil::EEndianness GetEndianness() const;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<enumerator ID="0x00" name="None"/>
|
<enumerator ID="0x00" name="None"/>
|
||||||
<enumerator ID="0x01" name="Snow"/>
|
<enumerator ID="0x01" name="Snow"/>
|
||||||
<enumerator ID="0x02" name="Rain"/>
|
<enumerator ID="0x02" name="Rain"/>
|
||||||
|
<enumerator ID="0x03" name="Bubbles"/>
|
||||||
</enumerators>
|
</enumerators>
|
||||||
</enum>
|
</enum>
|
||||||
<property ID="0x03" name="Initial Environmental Effect Density" type="float"/>
|
<property ID="0x03" name="Initial Environmental Effect Density" type="float"/>
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
<struct ID="0x08" name="DamageInfo 1" template="Structs/DamageInfo.xml"/>
|
<struct ID="0x08" name="DamageInfo 1" template="Structs/DamageInfo.xml"/>
|
||||||
<property ID="0x09" name="Unknown 3" type="long"/>
|
<property ID="0x09" name="Unknown 3" type="long"/>
|
||||||
<struct ID="0x0A" name="DamageInfo 2" template="Structs/DamageInfo.xml"/>
|
<struct ID="0x0A" name="DamageInfo 2" template="Structs/DamageInfo.xml"/>
|
||||||
<property ID="0x0B" name="Unknown 4" type="long"/>
|
<property ID="0x0B" name="Particle 1" type="file" extensions="PART"/>
|
||||||
<property ID="0x0C" name="Unknown 5" type="long"/>
|
<property ID="0x0C" name="Particle 2" type="file" extensions="PART"/>
|
||||||
<property ID="0x0D" name="Unknown 6" type="long"/>
|
<property ID="0x0D" name="Model 1" type="file" extensions="CMDL"/>
|
||||||
<struct ID="0x0E" name="FlareDef 1" template="Structs/FlareDef.xml"/>
|
<struct ID="0x0E" name="FlareDef 1" template="Structs/FlareDef.xml"/>
|
||||||
<struct ID="0x0F" name="FlareDef 2" template="Structs/FlareDef.xml"/>
|
<struct ID="0x0F" name="FlareDef 2" template="Structs/FlareDef.xml"/>
|
||||||
<struct ID="0x10" name="FlareDef 3" template="Structs/FlareDef.xml"/>
|
<struct ID="0x10" name="FlareDef 3" template="Structs/FlareDef.xml"/>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<property ID="0x16" name="Unknown 17" type="color"/>
|
<property ID="0x16" name="Unknown 17" type="color"/>
|
||||||
<property ID="0x17" name="Unknown 18" type="bool"/>
|
<property ID="0x17" name="Unknown 18" type="bool"/>
|
||||||
<property ID="0x18" name="Unknown 19" type="float"/>
|
<property ID="0x18" name="Unknown 19" type="float"/>
|
||||||
<property ID="0x19" name="Unknown 20" type="long"/>
|
<property ID="0x19" name="Particle" type="file" extensions="PART"/>
|
||||||
<property ID="0x1A" name="Unknown 21" type="long"/>
|
<property ID="0x1A" name="Unknown 21" type="long"/>
|
||||||
<property ID="0x1B" name="Unknown 22" type="long"/>
|
<property ID="0x1B" name="Unknown 22" type="long"/>
|
||||||
<property ID="0x1C" name="Unknown 23" type="long"/>
|
<property ID="0x1C" name="Unknown 23" type="long"/>
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
<property ID="0x03" name="Scale" type="vector3f"/>
|
<property ID="0x03" name="Scale" type="vector3f"/>
|
||||||
<struct ID="0x04" name="PatternedInfo" template="Structs/PatternedInfo.xml"/>
|
<struct ID="0x04" name="PatternedInfo" template="Structs/PatternedInfo.xml"/>
|
||||||
<struct ID="0x05" name="ActorParameters" template="Structs/ActorParameters.xml"/>
|
<struct ID="0x05" name="ActorParameters" template="Structs/ActorParameters.xml"/>
|
||||||
<property ID="0x06" name="Unknown 1" type="float"/>
|
<property ID="0x06" name="Unknown" type="float"/>
|
||||||
<property ID="0x07" name="Unknown 2" type="float"/>
|
<property ID="0x07" name="WPSC 1" type="file" extensions="WPSC"/>
|
||||||
<struct ID="0x08" name="DamageInfo" template="Structs/DamageInfo.xml"/>
|
<struct ID="0x08" name="DamageInfo" template="Structs/DamageInfo.xml"/>
|
||||||
<property ID="0x09" name="Particle 1" type="file" extensions="PART"/>
|
<property ID="0x09" name="Particle 1" type="file" extensions="PART"/>
|
||||||
<property ID="0x0A" name="Particle 2" type="file" extensions="PART"/>
|
<property ID="0x0A" name="Particle 2" type="file" extensions="PART"/>
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
<enumerator ID="0x01" name="Normal World Lighting"/>
|
<enumerator ID="0x01" name="Normal World Lighting"/>
|
||||||
<enumerator ID="0x02" name="Unknown 2"/>
|
<enumerator ID="0x02" name="Unknown 2"/>
|
||||||
<enumerator ID="0x03" name="Disable World Lighting"/>
|
<enumerator ID="0x03" name="Disable World Lighting"/>
|
||||||
|
<enumerator ID="0x04" name="Unknown 3"/>
|
||||||
|
<enumerator ID="0x05" name="Unknown 4"/>
|
||||||
</enumerators>
|
</enumerators>
|
||||||
</enum>
|
</enum>
|
||||||
<property ID="0x08" name="Light Recalculation Options" type="long"/>
|
<property ID="0x08" name="Light Recalculation Options" type="long"/>
|
||||||
|
|
Loading…
Reference in New Issue