Added editor game info system, exporter now fetches game build version, merged asset name maps for all games, resource browser can now import/export names to/from a map XML, reworked asset name generation to more closely match Retro's organization scheme, bug fixes
This commit is contained in:
parent
5ac292ebc5
commit
4f03c2431e
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<AssetList>
|
|
||||||
</AssetList>
|
|
|
@ -30,14 +30,14 @@ public:
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
inline void operator=(const u64& rkInput) { *this = CAssetID(rkInput); }
|
inline void operator= (const u64& rkInput) { *this = CAssetID(rkInput); }
|
||||||
inline void operator=(const char *pkInput) { *this = CAssetID(pkInput); }
|
inline void operator= (const char *pkInput) { *this = CAssetID(pkInput); }
|
||||||
inline bool operator==(const CAssetID& rkOther) const { return mLength == rkOther.mLength && mID == rkOther.mID; }
|
inline bool operator==(const CAssetID& rkOther) const { return mLength == rkOther.mLength && mID == rkOther.mID; }
|
||||||
inline bool operator!=(const CAssetID& rkOther) const { return mLength != rkOther.mLength || mID != rkOther.mID; }
|
inline bool operator!=(const CAssetID& rkOther) const { return mLength != rkOther.mLength || mID != rkOther.mID; }
|
||||||
inline bool operator>(const CAssetID& rkOther) const { return mID > rkOther.mID; }
|
inline bool operator> (const CAssetID& rkOther) const { return mLength >= rkOther.mLength && mID > rkOther.mID; }
|
||||||
inline bool operator>=(const CAssetID& rkOther) const { return mID >= rkOther.mID; }
|
inline bool operator>=(const CAssetID& rkOther) const { return mLength >= rkOther.mLength && mID >= rkOther.mID; }
|
||||||
inline bool operator<(const CAssetID& rkOther) const { return mID < rkOther.mID; }
|
inline bool operator< (const CAssetID& rkOther) const { return mLength < rkOther.mLength || mID < rkOther.mID; }
|
||||||
inline bool operator<=(const CAssetID& rkOther) const { return mID <= rkOther.mID; }
|
inline bool operator<=(const CAssetID& rkOther) const { return mLength < rkOther.mLength || mID <= rkOther.mID; }
|
||||||
inline bool operator==(u64 Other) const { return mID == Other; }
|
inline bool operator==(u64 Other) const { return mID == Other; }
|
||||||
inline bool operator!=(u64 Other) const { return mID != Other; }
|
inline bool operator!=(u64 Other) const { return mID != Other; }
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
virtual bool ParamBegin(const char*) { return true; }
|
virtual bool ParamBegin(const char*) { return true; }
|
||||||
virtual void ParamEnd() { }
|
virtual void ParamEnd() { }
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize) { SerializePrimitive(rSize); }
|
virtual void SerializeContainerSize(u32& rSize, const TString&) { SerializePrimitive(rSize); }
|
||||||
virtual void SerializeAbstractObjectType(u32& rType) { SerializePrimitive(rType); }
|
virtual void SerializeAbstractObjectType(u32& rType) { SerializePrimitive(rType); }
|
||||||
virtual void SerializePrimitive(bool& rValue) { rValue = mpStream->ReadBool(); }
|
virtual void SerializePrimitive(bool& rValue) { rValue = mpStream->ReadBool(); }
|
||||||
virtual void SerializePrimitive(char& rValue) { rValue = mpStream->ReadByte(); }
|
virtual void SerializePrimitive(char& rValue) { rValue = mpStream->ReadByte(); }
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
virtual bool ParamBegin(const char*) { return true; }
|
virtual bool ParamBegin(const char*) { return true; }
|
||||||
virtual void ParamEnd() { }
|
virtual void ParamEnd() { }
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize) { mpStream->WriteLong(rSize); }
|
virtual void SerializeContainerSize(u32& rSize, const TString&) { mpStream->WriteLong(rSize); }
|
||||||
virtual void SerializeAbstractObjectType(u32& rType) { mpStream->WriteLong(rType); }
|
virtual void SerializeAbstractObjectType(u32& rType) { mpStream->WriteLong(rType); }
|
||||||
virtual void SerializePrimitive(bool& rValue) { mpStream->WriteBool(rValue); }
|
virtual void SerializePrimitive(bool& rValue) { mpStream->WriteBool(rValue); }
|
||||||
virtual void SerializePrimitive(char& rValue) { mpStream->WriteByte(rValue); }
|
virtual void SerializePrimitive(char& rValue) { mpStream->WriteByte(rValue); }
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
mParamStack.pop_back();
|
mParamStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize)
|
virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/)
|
||||||
{
|
{
|
||||||
// Mostly handled by ParamBegin, we just need to return the size correctly so the container can be resized
|
// Mostly handled by ParamBegin, we just need to return the size correctly so the container can be resized
|
||||||
rSize = (u32) mpStream->PeekShort();
|
rSize = (u32) mpStream->PeekShort();
|
||||||
|
|
|
@ -91,7 +91,7 @@ public:
|
||||||
mParamStack.pop_back();
|
mParamStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize)
|
virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/)
|
||||||
{
|
{
|
||||||
// Normally handled by ParamBegin and ParamEnd but we need to do something here to account for zero-sized containers
|
// Normally handled by ParamBegin and ParamEnd but we need to do something here to account for zero-sized containers
|
||||||
if (rSize == 0)
|
if (rSize == 0)
|
||||||
|
|
|
@ -84,9 +84,12 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void SerializeContainerSize(u32& rSize)
|
virtual void SerializeContainerSize(u32& rSize, const TString& rkElemName)
|
||||||
{
|
{
|
||||||
rSize = TString(mpCurElem->Attribute("Size")).ToInt32(10);
|
rSize = 0;
|
||||||
|
|
||||||
|
for (tinyxml2::XMLElement *pElem = mpCurElem->FirstChildElement(*rkElemName); pElem; pElem = pElem->NextSiblingElement(*rkElemName))
|
||||||
|
rSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SerializeAbstractObjectType(u32& rType)
|
virtual void SerializeAbstractObjectType(u32& rType)
|
||||||
|
|
|
@ -58,9 +58,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void SerializeContainerSize(u32& rSize)
|
virtual void SerializeContainerSize(u32&, const TString&)
|
||||||
{
|
{
|
||||||
mpCurElem->SetAttribute("Size", (unsigned int) rSize);
|
// Reader obtains container size from number of child elements
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SerializeAbstractObjectType(u32& rType)
|
virtual void SerializeAbstractObjectType(u32& rType)
|
||||||
|
|
|
@ -372,7 +372,7 @@ public:
|
||||||
virtual bool ParamBegin(const char *pkName) = 0;
|
virtual bool ParamBegin(const char *pkName) = 0;
|
||||||
virtual void ParamEnd() = 0;
|
virtual void ParamEnd() = 0;
|
||||||
|
|
||||||
virtual void SerializeContainerSize(u32& rSize) = 0;
|
virtual void SerializeContainerSize(u32& rSize, const TString& rkElemName) = 0;
|
||||||
virtual void SerializeAbstractObjectType(u32& rType) = 0;
|
virtual void SerializeAbstractObjectType(u32& rType) = 0;
|
||||||
|
|
||||||
virtual void SerializePrimitive(bool& rValue) = 0;
|
virtual void SerializePrimitive(bool& rValue) = 0;
|
||||||
|
@ -431,10 +431,10 @@ public:
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
inline void SerializeContainerSize(IArchive& rArc, Container& rContainer)
|
inline void SerializeContainerSize(IArchive& rArc, Container& rContainer, const TString& rkElemName)
|
||||||
{
|
{
|
||||||
u32 Size = rContainer.size();
|
u32 Size = rContainer.size();
|
||||||
rArc.SerializeContainerSize(Size);
|
rArc.SerializeContainerSize(Size, rkElemName);
|
||||||
if (rArc.IsReader()) rContainer.resize(Size);
|
if (rArc.IsReader()) rContainer.resize(Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ inline void SerializeContainerSize(IArchive& rArc, Container& rContainer)
|
||||||
template<typename ValType>
|
template<typename ValType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName = "Item")
|
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName = "Item")
|
||||||
{
|
{
|
||||||
SerializeContainerSize(rArc, rVec);
|
SerializeContainerSize(rArc, rVec, rkElemName);
|
||||||
|
|
||||||
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
|
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
|
||||||
rArc << SERIAL(*rkElemName, rVec[iElem]);
|
rArc << SERIAL(*rkElemName, rVec[iElem]);
|
||||||
|
@ -451,7 +451,7 @@ inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const
|
||||||
template<typename ValType, typename FactoryType>
|
template<typename ValType, typename FactoryType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName, FactoryType *pFactory)
|
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName, FactoryType *pFactory)
|
||||||
{
|
{
|
||||||
SerializeContainerSize(rArc, rVec);
|
SerializeContainerSize(rArc, rVec, rkElemName);
|
||||||
|
|
||||||
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
|
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
|
||||||
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
|
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
|
||||||
|
@ -461,7 +461,7 @@ inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const
|
||||||
template<typename ValType>
|
template<typename ValType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName)
|
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName)
|
||||||
{
|
{
|
||||||
SerializeContainerSize(rArc, rList);
|
SerializeContainerSize(rArc, rList, rkElemName);
|
||||||
|
|
||||||
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
|
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
|
||||||
rArc << SERIAL(*rkElemName, *Iter);
|
rArc << SERIAL(*rkElemName, *Iter);
|
||||||
|
@ -470,7 +470,7 @@ inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const
|
||||||
template<typename ValType, typename FactoryType>
|
template<typename ValType, typename FactoryType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName, FactoryType *pFactory)
|
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName, FactoryType *pFactory)
|
||||||
{
|
{
|
||||||
SerializeContainerSize(rArc, rList);
|
SerializeContainerSize(rArc, rList, rkElemName);
|
||||||
|
|
||||||
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
|
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
|
||||||
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
|
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
|
||||||
|
@ -481,7 +481,7 @@ template<typename ValType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName)
|
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName)
|
||||||
{
|
{
|
||||||
u32 Size = rSet.size();
|
u32 Size = rSet.size();
|
||||||
rArc.SerializeContainerSize(Size);
|
rArc.SerializeContainerSize(Size, rkElemName);
|
||||||
|
|
||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
|
@ -507,7 +507,7 @@ template<typename ValType, typename FactoryType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName, FactoryType *pFactory)
|
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName, FactoryType *pFactory)
|
||||||
{
|
{
|
||||||
u32 Size = rSet.size();
|
u32 Size = rSet.size();
|
||||||
rArc.SerializeContainerSize(Size);
|
rArc.SerializeContainerSize(Size, rkElemName);
|
||||||
|
|
||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
|
@ -534,7 +534,7 @@ template<typename KeyType, typename ValType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::map<KeyType,ValType>& rMap, const TString& rkElemName)
|
inline void SerializeContainer(IArchive& rArc, std::map<KeyType,ValType>& rMap, const TString& rkElemName)
|
||||||
{
|
{
|
||||||
u32 Size = rMap.size();
|
u32 Size = rMap.size();
|
||||||
rArc.SerializeContainerSize(Size);
|
rArc.SerializeContainerSize(Size, rkElemName);
|
||||||
|
|
||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
|
@ -570,7 +570,7 @@ template<typename KeyType, typename ValType, typename FactoryType>
|
||||||
inline void SerializeContainer(IArchive& rArc, std::map<KeyType,ValType>& rMap, const TString& rkElemName, FactoryType *pFactory)
|
inline void SerializeContainer(IArchive& rArc, std::map<KeyType,ValType>& rMap, const TString& rkElemName, FactoryType *pFactory)
|
||||||
{
|
{
|
||||||
u32 Size = rMap.size();
|
u32 Size = rMap.size();
|
||||||
rArc.SerializeContainerSize(Size);
|
rArc.SerializeContainerSize(Size, rkElemName);
|
||||||
|
|
||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
|
|
|
@ -216,7 +216,8 @@ HEADERS += \
|
||||||
Resource/Animation/IMetaTransition.h \
|
Resource/Animation/IMetaTransition.h \
|
||||||
Resource/Animation/IMetaAnimation.h \
|
Resource/Animation/IMetaAnimation.h \
|
||||||
GameProject/CAssetNameMap.h \
|
GameProject/CAssetNameMap.h \
|
||||||
GameProject/AssetNameGeneration.h
|
GameProject/AssetNameGeneration.h \
|
||||||
|
GameProject/CGameInfo.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -320,4 +321,5 @@ SOURCES += \
|
||||||
Resource/Animation/IMetaAnimation.cpp \
|
Resource/Animation/IMetaAnimation.cpp \
|
||||||
Resource/Animation/IMetaTransition.cpp \
|
Resource/Animation/IMetaTransition.cpp \
|
||||||
GameProject/AssetNameGeneration.cpp \
|
GameProject/AssetNameGeneration.cpp \
|
||||||
GameProject/CAssetNameMap.cpp
|
GameProject/CAssetNameMap.cpp \
|
||||||
|
GameProject/CGameInfo.cpp
|
||||||
|
|
|
@ -38,6 +38,79 @@ void ApplyGeneratedName(CResourceEntry *pEntry, const TWideString& rkDir, const
|
||||||
ASSERT(Success);
|
ASSERT(Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TWideString MakeWorldName(EGame Game, TWideString RawName)
|
||||||
|
{
|
||||||
|
// MP1 demo - Remove ! from the beginning
|
||||||
|
if (Game == ePrimeDemo)
|
||||||
|
{
|
||||||
|
if (RawName.StartsWith(L'!'))
|
||||||
|
RawName = RawName.ChopFront(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MP1 - Remove prefix characters and ending date
|
||||||
|
else if (Game == ePrime)
|
||||||
|
{
|
||||||
|
RawName = RawName.ChopFront(2);
|
||||||
|
bool StartedDate = false;
|
||||||
|
|
||||||
|
while (!RawName.IsEmpty())
|
||||||
|
{
|
||||||
|
wchar_t Chr = RawName.Back();
|
||||||
|
|
||||||
|
if (!StartedDate && Chr >= L'0' && Chr <= L'9')
|
||||||
|
StartedDate = true;
|
||||||
|
else if (StartedDate && Chr != L'_' && (Chr < L'0' || Chr > L'9'))
|
||||||
|
break;
|
||||||
|
|
||||||
|
RawName = RawName.ChopBack(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MP2 demo - Use text between the first and second underscores
|
||||||
|
else if (Game == eEchoesDemo)
|
||||||
|
{
|
||||||
|
u32 UnderscoreA = RawName.IndexOf(L'_');
|
||||||
|
u32 UnderscoreB = RawName.IndexOf(L'_', UnderscoreA + 1);
|
||||||
|
RawName = RawName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MP3 proto - Remove ! from the beginning and all text after last underscore
|
||||||
|
else if (Game == eCorruptionProto)
|
||||||
|
{
|
||||||
|
if (RawName.StartsWith(L'!'))
|
||||||
|
RawName = RawName.ChopFront(1);
|
||||||
|
|
||||||
|
u32 LastUnderscore = RawName.LastIndexOf(L"_");
|
||||||
|
RawName = RawName.ChopBack(RawName.Size() - LastUnderscore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MP2/3 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
|
||||||
|
else if (Game == eEchoes || Game == eCorruption)
|
||||||
|
{
|
||||||
|
u32 FirstUnderscore = RawName.IndexOf(L'_');
|
||||||
|
u32 LastUnderscore = RawName.LastIndexOf(L"_");
|
||||||
|
|
||||||
|
if (FirstUnderscore != LastUnderscore)
|
||||||
|
{
|
||||||
|
RawName = RawName.ChopBack(RawName.Size() - LastUnderscore);
|
||||||
|
RawName = RawName.ChopFront(FirstUnderscore + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
RawName.Remove(L'_');
|
||||||
|
}
|
||||||
|
|
||||||
|
// DKCR - Remove text after second-to-last underscore
|
||||||
|
else if (Game == eReturns)
|
||||||
|
{
|
||||||
|
u32 Underscore = RawName.LastIndexOf(L"_");
|
||||||
|
RawName = RawName.ChopBack(RawName.Size() - Underscore);
|
||||||
|
Underscore = RawName.LastIndexOf(L"_");
|
||||||
|
RawName = RawName.ChopBack(RawName.Size() - Underscore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RawName;
|
||||||
|
}
|
||||||
|
|
||||||
void GenerateAssetNames(CGameProject *pProj)
|
void GenerateAssetNames(CGameProject *pProj)
|
||||||
{
|
{
|
||||||
// todo: CAUD/CSMP
|
// todo: CAUD/CSMP
|
||||||
|
@ -69,34 +142,17 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
|
|
||||||
for (TResourceIterator<eWorld> It(pStore); It; ++It)
|
for (TResourceIterator<eWorld> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
// World common stuff
|
// Generate world name
|
||||||
TWideString WorldName = It->Name();
|
TWideString WorldName = MakeWorldName(pProj->Game(), It->Name());
|
||||||
|
|
||||||
// Remove date from the end of the world name
|
|
||||||
if (WorldName.EndsWith(L"_#SERIAL#"))
|
|
||||||
WorldName = WorldName.ChopBack(9);
|
|
||||||
|
|
||||||
// Verify the second-to-last character is a number to make sure there is actually a date in the world name
|
|
||||||
// note MP2 multiplayer worlds do not have dates in their names
|
|
||||||
else if (WorldName[WorldName.Size() - 2] >= '0' && WorldName[WorldName.Size() - 2] <= '9')
|
|
||||||
{
|
|
||||||
bool StartedDate = false;
|
|
||||||
|
|
||||||
while (!WorldName.IsEmpty())
|
|
||||||
{
|
|
||||||
wchar_t Chr = WorldName.Back();
|
|
||||||
|
|
||||||
if (!StartedDate && Chr >= L'0' && Chr <= L'9')
|
|
||||||
StartedDate = true;
|
|
||||||
else if (StartedDate && Chr != L'_' && (Chr < L'0' || Chr > L'9'))
|
|
||||||
break;
|
|
||||||
|
|
||||||
WorldName = WorldName.ChopBack(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TWideString WorldDir = kWorldsRoot + WorldName + L'\\';
|
TWideString WorldDir = kWorldsRoot + WorldName + L'\\';
|
||||||
ApplyGeneratedName(*It, WorldDir, WorldName);
|
|
||||||
|
TWideString WorldMasterName = L"!" + WorldName + L"_Master";
|
||||||
|
TWideString WorldMasterDir = WorldDir + WorldMasterName + L'\\';
|
||||||
|
ApplyGeneratedName(*It, WorldMasterDir, WorldMasterName);
|
||||||
|
|
||||||
|
// Move world stuff
|
||||||
|
const TWideString WorldNamesDir = L"Strings\\Worlds\\General\\";
|
||||||
|
const TWideString AreaNamesDir = TWideString::Format(L"Strings\\Worlds\\%s\\", *WorldName);
|
||||||
|
|
||||||
CWorld *pWorld = (CWorld*) It->Load();
|
CWorld *pWorld = (CWorld*) It->Load();
|
||||||
CModel *pSkyModel = pWorld->DefaultSkybox();
|
CModel *pSkyModel = pWorld->DefaultSkybox();
|
||||||
|
@ -105,53 +161,68 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
CResource *pSaveWorld = pWorld->SaveWorld();
|
CResource *pSaveWorld = pWorld->SaveWorld();
|
||||||
CResource *pMapWorld = pWorld->MapWorld();
|
CResource *pMapWorld = pWorld->MapWorld();
|
||||||
|
|
||||||
|
if (pSaveWorld)
|
||||||
|
ApplyGeneratedName(pSaveWorld->Entry(), WorldMasterDir, WorldMasterName);
|
||||||
|
|
||||||
|
if (pMapWorld)
|
||||||
|
ApplyGeneratedName(pMapWorld->Entry(), WorldMasterDir, WorldMasterName);
|
||||||
|
|
||||||
if (pSkyModel && !pSkyModel->Entry()->IsCategorized())
|
if (pSkyModel && !pSkyModel->Entry()->IsCategorized())
|
||||||
{
|
{
|
||||||
|
// Move sky model
|
||||||
CResourceEntry *pSkyEntry = pSkyModel->Entry();
|
CResourceEntry *pSkyEntry = pSkyModel->Entry();
|
||||||
ApplyGeneratedName(pSkyEntry, WorldDir, TWideString::Format(L"%s_Sky", *WorldName));
|
ApplyGeneratedName(pSkyEntry, WorldDir + L"sky\\cooked\\", L"sky");
|
||||||
|
|
||||||
|
// Move sky textures
|
||||||
|
for (u32 iSet = 0; iSet < pSkyModel->GetMatSetCount(); iSet++)
|
||||||
|
{
|
||||||
|
CMaterialSet *pSet = pSkyModel->GetMatSet(iSet);
|
||||||
|
|
||||||
|
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
||||||
|
{
|
||||||
|
CMaterial *pMat = pSet->MaterialByIndex(iMat);
|
||||||
|
|
||||||
|
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
|
{
|
||||||
|
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||||
|
|
||||||
|
if (pPass->Texture() && !pPass->Texture()->Entry()->IsCategorized())
|
||||||
|
ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + L"sky\\sourceimages\\", pPass->Texture()->Entry()->Name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pWorldNameTable)
|
if (pWorldNameTable)
|
||||||
{
|
{
|
||||||
CResourceEntry *pNameEntry = pWorldNameTable->Entry();
|
CResourceEntry *pNameEntry = pWorldNameTable->Entry();
|
||||||
ApplyGeneratedName(pNameEntry, WorldDir, pNameEntry->Name());
|
ApplyGeneratedName(pNameEntry, WorldNamesDir, WorldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDarkWorldNameTable)
|
if (pDarkWorldNameTable)
|
||||||
{
|
{
|
||||||
CResourceEntry *pDarkNameEntry = pDarkWorldNameTable->Entry();
|
CResourceEntry *pDarkNameEntry = pDarkWorldNameTable->Entry();
|
||||||
ApplyGeneratedName(pDarkNameEntry, WorldDir, pDarkNameEntry->Name());
|
ApplyGeneratedName(pDarkNameEntry, WorldNamesDir, WorldName + L"Dark");
|
||||||
}
|
}
|
||||||
if (pSaveWorld)
|
|
||||||
ApplyGeneratedName(pSaveWorld->Entry(), WorldDir, TWideString::Format(L"%s_SaveInfo", *WorldName));
|
|
||||||
|
|
||||||
if (pMapWorld)
|
|
||||||
ApplyGeneratedName(pMapWorld->Entry(), WorldDir, TWideString::Format(L"%s_Map", *WorldName));
|
|
||||||
|
|
||||||
// Areas
|
// Areas
|
||||||
for (u32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
for (u32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
// Determine area name
|
// Determine area name
|
||||||
|
TWideString AreaName = pWorld->AreaInternalName(iArea).ToUTF16();
|
||||||
CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
||||||
TString InternalAreaName = pWorld->AreaInternalName(iArea);
|
|
||||||
CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
|
|
||||||
TWideString AreaName;
|
|
||||||
|
|
||||||
if (pAreaNameTable)
|
if (AreaName.IsEmpty())
|
||||||
AreaName = pAreaNameTable->String("ENGL", 0);
|
AreaName = AreaID.ToString().ToUTF16();
|
||||||
else if (!InternalAreaName.IsEmpty())
|
|
||||||
AreaName = L"!!" + InternalAreaName.ToUTF16();
|
|
||||||
else
|
|
||||||
AreaName = L"!!" + AreaID.ToString().ToUTF16();
|
|
||||||
|
|
||||||
TWideString AreaDir = TWideString::Format(L"%s%02d_%s\\", *WorldDir, iArea, *AreaName);
|
|
||||||
|
|
||||||
// Rename area stuff
|
// Rename area stuff
|
||||||
CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID);
|
CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID);
|
||||||
ASSERT(pAreaEntry != nullptr);
|
ASSERT(pAreaEntry != nullptr);
|
||||||
ApplyGeneratedName(pAreaEntry, AreaDir, AreaName);
|
ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName);
|
||||||
|
|
||||||
|
CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
|
||||||
if (pAreaNameTable)
|
if (pAreaNameTable)
|
||||||
ApplyGeneratedName(pAreaNameTable->Entry(), AreaDir, pAreaNameTable->Entry()->Name());
|
ApplyGeneratedName(pAreaNameTable->Entry(), AreaNamesDir, AreaName);
|
||||||
|
|
||||||
if (pMapWorld)
|
if (pMapWorld)
|
||||||
{
|
{
|
||||||
|
@ -161,128 +232,149 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
CResourceEntry *pMapEntry = pStore->FindEntry(MapID);
|
CResourceEntry *pMapEntry = pStore->FindEntry(MapID);
|
||||||
ASSERT(pMapEntry != nullptr);
|
ASSERT(pMapEntry != nullptr);
|
||||||
|
|
||||||
ApplyGeneratedName(pMapEntry, AreaDir, TWideString::Format(L"%s_Map", *AreaName));
|
ApplyGeneratedName(pMapEntry, WorldMasterDir, AreaName);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PROCESS_AREAS
|
#if PROCESS_AREAS
|
||||||
// Generate area stuff
|
// Move area dependencies
|
||||||
for (TResourceIterator<eArea> It(pStore); It; ++It)
|
TWideString AreaCookedDir = WorldDir + AreaName + L"\\cooked\\";
|
||||||
{
|
CGameArea *pArea = (CGameArea*) pAreaEntry->Load();
|
||||||
TWideString AreaDir = It->DirectoryPath();
|
|
||||||
TWideString AreaName = It->Name();
|
|
||||||
CGameArea *pArea = (CGameArea*) It->Load();
|
|
||||||
|
|
||||||
// Area lightmaps
|
// Area lightmaps
|
||||||
TWideString LightmapDir = AreaDir + L"Lightmaps\\";
|
u32 LightmapNum = 0;
|
||||||
CMaterialSet *pMaterials = pArea->Materials();
|
CMaterialSet *pMaterials = pArea->Materials();
|
||||||
|
|
||||||
for (u32 iMat = 0; iMat < pMaterials->NumMaterials(); iMat++)
|
for (u32 iMat = 0; iMat < pMaterials->NumMaterials(); iMat++)
|
||||||
{
|
|
||||||
CMaterial *pMat = pMaterials->MaterialByIndex(iMat);
|
|
||||||
|
|
||||||
if (pMat->Options().HasFlag(CMaterial::eLightmap))
|
|
||||||
{
|
{
|
||||||
CTexture *pLightmapTex = pMat->Pass(0)->Texture();
|
CMaterial *pMat = pMaterials->MaterialByIndex(iMat);
|
||||||
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
|
||||||
|
|
||||||
TWideString TexName = TWideString::Format(L"lit_%s_%dx%d", *pLightmapTex->ID().ToString().ToUTF16(), pLightmapTex->Width(), pLightmapTex->Height());
|
if (pMat->Options().HasFlag(CMaterial::eLightmap))
|
||||||
ApplyGeneratedName(pTexEntry, LightmapDir, TexName);
|
|
||||||
pTexEntry->SetHidden(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate names from script instance names
|
|
||||||
for (u32 iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++)
|
|
||||||
{
|
|
||||||
CScriptLayer *pLayer = pArea->ScriptLayer(iLyr);
|
|
||||||
|
|
||||||
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
|
||||||
{
|
|
||||||
CScriptObject *pInst = pLayer->InstanceByIndex(iInst);
|
|
||||||
|
|
||||||
if (pInst->ObjectTypeID() == 0x42 || pInst->ObjectTypeID() == FOURCC("POIN"))
|
|
||||||
{
|
{
|
||||||
TString Name = pInst->InstanceName();
|
CTexture *pLightmapTex = pMat->Pass(0)->Texture();
|
||||||
|
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
||||||
|
if (pTexEntry->IsCategorized()) continue;
|
||||||
|
|
||||||
if (Name.EndsWith(".SCAN", false))
|
TWideString TexName = TWideString::Format(L"%s_lit_lightmap%d", *AreaName, LightmapNum);
|
||||||
|
ApplyGeneratedName(pTexEntry, AreaCookedDir, TexName);
|
||||||
|
pTexEntry->SetHidden(true);
|
||||||
|
LightmapNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate names from script instance names
|
||||||
|
for (u32 iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++)
|
||||||
|
{
|
||||||
|
CScriptLayer *pLayer = pArea->ScriptLayer(iLyr);
|
||||||
|
|
||||||
|
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||||
|
{
|
||||||
|
CScriptObject *pInst = pLayer->InstanceByIndex(iInst);
|
||||||
|
|
||||||
|
if (pInst->ObjectTypeID() == 0x42 || pInst->ObjectTypeID() == FOURCC("POIN"))
|
||||||
{
|
{
|
||||||
TIDString ScanIDString = (pProj->Game() <= ePrime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7");
|
TString Name = pInst->InstanceName();
|
||||||
TAssetProperty *pScanProperty = TPropCast<TAssetProperty>(pInst->PropertyByIDString(ScanIDString));
|
|
||||||
ASSERT(pScanProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
|
||||||
|
|
||||||
if (pScanProperty)
|
if (Name.EndsWith(".SCAN", false))
|
||||||
{
|
{
|
||||||
CAssetID ScanID = pScanProperty->Get();
|
TIDString ScanIDString = (pProj->Game() <= ePrime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7");
|
||||||
CResourceEntry *pEntry = pStore->FindEntry(ScanID);
|
TAssetProperty *pScanProperty = TPropCast<TAssetProperty>(pInst->PropertyByIDString(ScanIDString));
|
||||||
|
ASSERT(pScanProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||||
|
|
||||||
if (pEntry && !pEntry->IsNamed())
|
if (pScanProperty)
|
||||||
{
|
{
|
||||||
TWideString ScanName = Name.ToUTF16().ChopBack(5);
|
CAssetID ScanID = pScanProperty->Get();
|
||||||
|
CResourceEntry *pEntry = pStore->FindEntry(ScanID);
|
||||||
|
|
||||||
if (ScanName.StartsWith(L"POI_"))
|
if (pEntry && !pEntry->IsNamed())
|
||||||
ScanName = ScanName.ChopFront(4);
|
|
||||||
|
|
||||||
ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), ScanName);
|
|
||||||
|
|
||||||
CScan *pScan = (CScan*) pEntry->Load();
|
|
||||||
if (pScan && pScan->ScanText())
|
|
||||||
{
|
{
|
||||||
CResourceEntry *pStringEntry = pScan->ScanText()->Entry();
|
TWideString ScanName = Name.ToUTF16().ChopBack(5);
|
||||||
ApplyGeneratedName(pStringEntry, pStringEntry->DirectoryPath(), ScanName);
|
|
||||||
|
if (ScanName.StartsWith(L"POI_"))
|
||||||
|
ScanName = ScanName.ChopFront(4);
|
||||||
|
|
||||||
|
ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), ScanName);
|
||||||
|
|
||||||
|
CScan *pScan = (CScan*) pEntry->Load();
|
||||||
|
if (pScan && pScan->ScanText())
|
||||||
|
{
|
||||||
|
CResourceEntry *pStringEntry = pScan->ScanText()->Entry();
|
||||||
|
ApplyGeneratedName(pStringEntry, pStringEntry->DirectoryPath(), ScanName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (pInst->ObjectTypeID() == 0x17 || pInst->ObjectTypeID() == FOURCC("MEMO"))
|
else if (pInst->ObjectTypeID() == 0x17 || pInst->ObjectTypeID() == FOURCC("MEMO"))
|
||||||
{
|
|
||||||
TString Name = pInst->InstanceName();
|
|
||||||
|
|
||||||
if (Name.EndsWith(".STRG", false))
|
|
||||||
{
|
{
|
||||||
u32 StringPropID = (pProj->Game() <= ePrime ? 0x4 : 0x9182250C);
|
TString Name = pInst->InstanceName();
|
||||||
TAssetProperty *pStringProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(StringPropID));
|
|
||||||
ASSERT(pStringProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
|
||||||
|
|
||||||
if (pStringProperty)
|
if (Name.EndsWith(".STRG", false))
|
||||||
{
|
{
|
||||||
CAssetID StringID = pStringProperty->Get();
|
u32 StringPropID = (pProj->Game() <= ePrime ? 0x4 : 0x9182250C);
|
||||||
CResourceEntry *pEntry = pStore->FindEntry(StringID);
|
TAssetProperty *pStringProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(StringPropID));
|
||||||
|
ASSERT(pStringProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||||
|
|
||||||
if (pEntry && !pEntry->IsNamed())
|
if (pStringProperty)
|
||||||
{
|
{
|
||||||
TWideString StringName = Name.ToUTF16().ChopBack(5);
|
CAssetID StringID = pStringProperty->Get();
|
||||||
|
CResourceEntry *pEntry = pStore->FindEntry(StringID);
|
||||||
|
|
||||||
if (StringName.StartsWith(L"HUDMemo - "))
|
if (pEntry && !pEntry->IsNamed())
|
||||||
StringName = StringName.ChopFront(10);
|
{
|
||||||
|
TWideString StringName = Name.ToUTF16().ChopBack(5);
|
||||||
|
|
||||||
ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), StringName);
|
if (StringName.StartsWith(L"HUDMemo - "))
|
||||||
|
StringName = StringName.ChopFront(10);
|
||||||
|
|
||||||
|
ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), StringName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for lightmapped models - these are going to be unique to this area
|
||||||
|
else if (pInst->ObjectTypeID() == 0x0 || pInst->ObjectTypeID() == FOURCC("ACTR") ||
|
||||||
|
pInst->ObjectTypeID() == 0x8 || pInst->ObjectTypeID() == FOURCC("PLAT"))
|
||||||
|
{
|
||||||
|
u32 ModelPropID = (pProj->Game() <= ePrime ? (pInst->ObjectTypeID() == 0x0 ? 0xA : 0x6) : 0xC27FFA8F);
|
||||||
|
TAssetProperty *pModelProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(ModelPropID));
|
||||||
|
ASSERT(pModelProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||||
|
|
||||||
|
if (pModelProperty)
|
||||||
|
{
|
||||||
|
CAssetID ModelID = pModelProperty->Get();
|
||||||
|
CResourceEntry *pEntry = pStore->FindEntry(ModelID);
|
||||||
|
|
||||||
|
if (pEntry && !pEntry->IsCategorized())
|
||||||
|
{
|
||||||
|
CModel *pModel = (CModel*) pEntry->Load();
|
||||||
|
|
||||||
|
if (pModel->IsLightmapped())
|
||||||
|
ApplyGeneratedName(pEntry, AreaCookedDir, pEntry->Name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Other area assets
|
||||||
|
CResourceEntry *pPathEntry = pStore->FindEntry(pArea->PathID());
|
||||||
|
CResourceEntry *pPoiMapEntry = pArea->PoiToWorldMap() ? pArea->PoiToWorldMap()->Entry() : nullptr;
|
||||||
|
CResourceEntry *pPortalEntry = pStore->FindEntry(pArea->PortalAreaID());
|
||||||
|
|
||||||
|
if (pPathEntry)
|
||||||
|
ApplyGeneratedName(pPathEntry, WorldMasterDir, AreaName);
|
||||||
|
|
||||||
|
if (pPoiMapEntry)
|
||||||
|
ApplyGeneratedName(pPoiMapEntry, WorldMasterDir, AreaName);
|
||||||
|
|
||||||
|
if (pPortalEntry)
|
||||||
|
ApplyGeneratedName(pPortalEntry, WorldMasterDir, AreaName);
|
||||||
|
|
||||||
|
pStore->DestroyUnreferencedResources();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other area assets
|
|
||||||
CResourceEntry *pPathEntry = pStore->FindEntry(pArea->PathID());
|
|
||||||
CResourceEntry *pPoiMapEntry = pArea->PoiToWorldMap() ? pArea->PoiToWorldMap()->Entry() : nullptr;
|
|
||||||
CResourceEntry *pPortalEntry = pStore->FindEntry(pArea->PortalAreaID());
|
|
||||||
|
|
||||||
if (pPathEntry)
|
|
||||||
ApplyGeneratedName(pPathEntry, AreaDir, TWideString::Format(L"%s_Path", *AreaName));
|
|
||||||
|
|
||||||
if (pPoiMapEntry)
|
|
||||||
ApplyGeneratedName(pPoiMapEntry, AreaDir, TWideString::Format(L"%s_EGMC", *AreaName));
|
|
||||||
|
|
||||||
if (pPortalEntry)
|
|
||||||
ApplyGeneratedName(pPortalEntry, AreaDir, TWideString::Format(L"%s_PortalArea", *AreaName));
|
|
||||||
|
|
||||||
pStore->DestroyUnreferencedResources();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -291,6 +383,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
for (TResourceIterator<eModel> It(pStore); It; ++It)
|
for (TResourceIterator<eModel> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
CModel *pModel = (CModel*) It->Load();
|
CModel *pModel = (CModel*) It->Load();
|
||||||
|
u32 LightmapNum = 0;
|
||||||
|
|
||||||
for (u32 iSet = 0; iSet < pModel->GetMatSetCount(); iSet++)
|
for (u32 iSet = 0; iSet < pModel->GetMatSetCount(); iSet++)
|
||||||
{
|
{
|
||||||
|
@ -306,9 +399,10 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
||||||
if (pTexEntry->IsNamed() || pTexEntry->IsCategorized()) continue;
|
if (pTexEntry->IsNamed() || pTexEntry->IsCategorized()) continue;
|
||||||
|
|
||||||
TWideString TexName = TWideString::Format(L"lit_%s_%dx%d", *pLightmapTex->ID().ToString().ToUTF16(), pLightmapTex->Width(), pLightmapTex->Height());
|
TWideString TexName = TWideString::Format(L"%s_lightmap%d", *It->Name(), LightmapNum);
|
||||||
ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName);
|
ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName);
|
||||||
pTexEntry->SetHidden(true);
|
pTexEntry->SetHidden(true);
|
||||||
|
LightmapNum++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
#include "CAssetNameMap.h"
|
#include "CAssetNameMap.h"
|
||||||
|
|
||||||
std::map<EGame, CAssetNameMap*> CAssetNameMap::smGameMap;
|
void CAssetNameMap::LoadAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||||
|
|
||||||
CAssetNameMap::CAssetNameMap(EGame Game)
|
|
||||||
: mGame(Game)
|
|
||||||
{
|
{
|
||||||
TString ListPath = GetAssetListPath(mGame);
|
CXMLReader Reader(Path);
|
||||||
CXMLReader Reader(ListPath);
|
|
||||||
Serialize(Reader);
|
Serialize(Reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAssetNameMap::SaveAssetNames()
|
void CAssetNameMap::SaveAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||||
{
|
{
|
||||||
TString ListPath = GetAssetListPath(mGame);
|
CXMLWriter Writer(Path, "AssetNameMap", 0, eUnknownGame);
|
||||||
CXMLWriter Writer(ListPath, "AssetList", 0, mGame);
|
|
||||||
Serialize(Writer);
|
Serialize(Writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName)
|
bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName)
|
||||||
{
|
{
|
||||||
auto It = mMap.find(ID);
|
auto It = mMap.find(ID);
|
||||||
|
|
||||||
|
@ -26,12 +21,14 @@ void CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rO
|
||||||
SAssetNameInfo& rInfo = It->second;
|
SAssetNameInfo& rInfo = It->second;
|
||||||
rOutName = rInfo.Name;
|
rOutName = rInfo.Name;
|
||||||
rOutDirectory = rInfo.Directory;
|
rOutDirectory = rInfo.Directory;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rOutDirectory = "Uncategorized\\";
|
rOutDirectory = "Uncategorized\\";
|
||||||
rOutName = ID.ToString();
|
rOutName = ID.ToString();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
const TString gkAssetListDir = "..\\resources\\list\\";
|
const TString gkAssetMapPath = "..\\resources\\gameinfo\\AssetNameMap.xml";
|
||||||
|
|
||||||
class CAssetNameMap
|
class CAssetNameMap
|
||||||
{
|
{
|
||||||
|
@ -23,38 +23,19 @@ class CAssetNameMap
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EGame mGame;
|
|
||||||
std::map<CAssetID, SAssetNameInfo> mMap;
|
std::map<CAssetID, SAssetNameInfo> mMap;
|
||||||
static std::map<EGame, CAssetNameMap*> smGameMap;
|
|
||||||
|
|
||||||
// Private Methods
|
// Private Methods
|
||||||
CAssetNameMap(EGame Game);
|
|
||||||
|
|
||||||
void Serialize(IArchive& rArc)
|
void Serialize(IArchive& rArc)
|
||||||
{
|
{
|
||||||
rArc << SERIAL_CONTAINER("AssetNameMap", mMap, "Asset");
|
rArc << SERIAL_CONTAINER("AssetNameMap", mMap, "Asset");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SaveAssetNames();
|
void LoadAssetNames(TString Path = gkAssetMapPath);
|
||||||
void GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName);
|
void SaveAssetNames(TString Path = gkAssetMapPath);
|
||||||
|
bool GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName);
|
||||||
void CopyFromStore(CResourceStore *pStore);
|
void CopyFromStore(CResourceStore *pStore);
|
||||||
|
|
||||||
// Static Methods
|
|
||||||
static TString GetAssetListPath(EGame Game)
|
|
||||||
{
|
|
||||||
return gkAssetListDir + "AssetList" + GetGameShortName(Game) + ".xml";
|
|
||||||
}
|
|
||||||
|
|
||||||
static CAssetNameMap* GetGameNameMap(EGame Game)
|
|
||||||
{
|
|
||||||
auto Find = smGameMap.find(Game);
|
|
||||||
if (Find != smGameMap.end()) return Find->second;
|
|
||||||
|
|
||||||
CAssetNameMap *pMap = new CAssetNameMap(Game);
|
|
||||||
smGameMap[Game] = pMap;
|
|
||||||
return pMap;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CASSETNAMEMAP
|
#endif // CASSETNAMEMAP
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "CGameExporter.h"
|
#include "CGameExporter.h"
|
||||||
#include "Core/GameProject/CResourceIterator.h"
|
#include "CGameInfo.h"
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "CResourceIterator.h"
|
||||||
|
#include "CResourceStore.h"
|
||||||
#include "Core/Resource/CWorld.h"
|
#include "Core/Resource/CWorld.h"
|
||||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||||
#include <FileIO/FileIO.h>
|
#include <FileIO/FileIO.h>
|
||||||
|
@ -14,13 +15,14 @@
|
||||||
#define COPY_DISC_DATA 1
|
#define COPY_DISC_DATA 1
|
||||||
#define LOAD_PAKS 1
|
#define LOAD_PAKS 1
|
||||||
#define SAVE_PACKAGE_DEFINITIONS 1
|
#define SAVE_PACKAGE_DEFINITIONS 1
|
||||||
#define USE_ASSET_NAME_MAP 0
|
#define USE_ASSET_NAME_MAP 1
|
||||||
#define EXPORT_COOKED 1
|
#define EXPORT_COOKED 1
|
||||||
|
|
||||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||||
: mpNameMap(nullptr)
|
|
||||||
{
|
{
|
||||||
mGame = eUnknownGame;
|
mGame = eUnknownGame;
|
||||||
|
mBuildVersion = 0.f;
|
||||||
|
|
||||||
mGameDir = FileUtil::MakeAbsolute(rkInputDir);
|
mGameDir = FileUtil::MakeAbsolute(rkInputDir);
|
||||||
mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
|
mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
|
||||||
|
|
||||||
|
@ -42,9 +44,10 @@ bool CGameExporter::Export()
|
||||||
|
|
||||||
// Initial analyze/copy of disc data
|
// Initial analyze/copy of disc data
|
||||||
CopyDiscData();
|
CopyDiscData();
|
||||||
|
FindBuildVersion();
|
||||||
|
|
||||||
// Create project
|
// Create project
|
||||||
mpProject = new CGameProject(this, mExportDir, mGame);
|
mpProject = new CGameProject(this, mExportDir, mGame, mBuildVersion);
|
||||||
mpProject->SetProjectName(CMasterTemplate::FindGameName(mGame));
|
mpProject->SetProjectName(CMasterTemplate::FindGameName(mGame));
|
||||||
mpProject->SetActive();
|
mpProject->SetActive();
|
||||||
mpStore = mpProject->ResourceStore();
|
mpStore = mpProject->ResourceStore();
|
||||||
|
@ -52,7 +55,7 @@ bool CGameExporter::Export()
|
||||||
mCookedDir = mpStore->CookedDir(false);
|
mCookedDir = mpStore->CookedDir(false);
|
||||||
|
|
||||||
#if USE_ASSET_NAME_MAP
|
#if USE_ASSET_NAME_MAP
|
||||||
mpNameMap = CAssetNameMap::GetGameNameMap(mGame);
|
mNameMap.LoadAssetNames();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Export game data
|
// Export game data
|
||||||
|
@ -113,6 +116,10 @@ void CGameExporter::CopyDiscData()
|
||||||
else if (Name == L"PreloadData") mGame = eReturns;
|
else if (Name == L"PreloadData") mGame = eReturns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dol path. Note size != 0 check is needed because some ISO unpackers (*cough* GCRebuilder) can export bad dol files
|
||||||
|
if (mDolPath.IsEmpty() && FullPath.EndsWith(L".dol", false) && FileUtil::FileSize(FullPath) != 0)
|
||||||
|
mDolPath = FullPath;
|
||||||
|
|
||||||
// Detect paks
|
// Detect paks
|
||||||
if (FullPath.GetFileExtension().ToLower() == L"pak")
|
if (FullPath.GetFileExtension().ToLower() == L"pak")
|
||||||
mPaks.push_back(FullPath);
|
mPaks.push_back(FullPath);
|
||||||
|
@ -131,6 +138,45 @@ void CGameExporter::CopyDiscData()
|
||||||
ASSERT(mGame != eUnknownGame);
|
ASSERT(mGame != eUnknownGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameExporter::FindBuildVersion()
|
||||||
|
{
|
||||||
|
ASSERT(!mDolPath.IsEmpty());
|
||||||
|
|
||||||
|
// MP1 demo build doesn't have a build version
|
||||||
|
if (mGame == ePrimeDemo) return;
|
||||||
|
|
||||||
|
// Read entire file into a big buffer
|
||||||
|
CFileInStream File(mDolPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
|
||||||
|
std::vector<char> FileContents(File.Size());
|
||||||
|
File.ReadBytes(FileContents.data(), FileContents.size());
|
||||||
|
File.Close();
|
||||||
|
|
||||||
|
// Find build info string
|
||||||
|
const char *pkSearchText = "!#$MetroidBuildInfo!#$";
|
||||||
|
const int SearchTextSize = strlen(pkSearchText);
|
||||||
|
|
||||||
|
for (u32 SearchIdx = 0; SearchIdx < FileContents.size() - SearchTextSize + 1; SearchIdx++)
|
||||||
|
{
|
||||||
|
int Match = 0;
|
||||||
|
|
||||||
|
while (FileContents[SearchIdx + Match] == pkSearchText[Match] && Match < SearchTextSize)
|
||||||
|
Match++;
|
||||||
|
|
||||||
|
if (Match == SearchTextSize)
|
||||||
|
{
|
||||||
|
// Found the build info string; extract version number
|
||||||
|
TString BuildInfo = &FileContents[SearchIdx + SearchTextSize];
|
||||||
|
int BuildVerStart = BuildInfo.IndexOfPhrase("Build v") + 7;
|
||||||
|
ASSERT(BuildVerStart != 6);
|
||||||
|
|
||||||
|
mBuildVersion = BuildInfo.SubString(BuildVerStart, 5).ToFloat();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::Error("Failed to find MetroidBuildInfo string. Build Version will be set to 0. DOL file: " + mDolPath.ToUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
// ************ RESOURCE LOADING ************
|
// ************ RESOURCE LOADING ************
|
||||||
void CGameExporter::LoadPaks()
|
void CGameExporter::LoadPaks()
|
||||||
{
|
{
|
||||||
|
@ -471,7 +517,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
|
|
||||||
// Register resource and write to file
|
// Register resource and write to file
|
||||||
TString Directory, Name;
|
TString Directory, Name;
|
||||||
mpNameMap->GetNameInfo(rRes.ResourceID, Directory, Name);
|
mNameMap.GetNameInfo(rRes.ResourceID, Directory, Name);
|
||||||
CResourceEntry *pEntry = mpStore->RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), Directory, Name);
|
CResourceEntry *pEntry = mpStore->RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), Directory, Name);
|
||||||
|
|
||||||
#if EXPORT_COOKED
|
#if EXPORT_COOKED
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CGAMEEXPORTER_H
|
#define CGAMEEXPORTER_H
|
||||||
|
|
||||||
#include "CAssetNameMap.h"
|
#include "CAssetNameMap.h"
|
||||||
|
#include "CGameInfo.h"
|
||||||
#include "CGameProject.h"
|
#include "CGameProject.h"
|
||||||
#include "CResourceStore.h"
|
#include "CResourceStore.h"
|
||||||
#include <Common/CAssetID.h>
|
#include <Common/CAssetID.h>
|
||||||
|
@ -16,6 +17,7 @@ class CGameExporter
|
||||||
CGameProject *mpProject;
|
CGameProject *mpProject;
|
||||||
CResourceStore *mpStore;
|
CResourceStore *mpStore;
|
||||||
EGame mGame;
|
EGame mGame;
|
||||||
|
float mBuildVersion;
|
||||||
|
|
||||||
// Directories
|
// Directories
|
||||||
TWideString mGameDir;
|
TWideString mGameDir;
|
||||||
|
@ -26,10 +28,14 @@ class CGameExporter
|
||||||
|
|
||||||
TWideString mWorldsDirName;
|
TWideString mWorldsDirName;
|
||||||
|
|
||||||
|
// Files
|
||||||
|
TWideString mDolPath;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
TWideStringList mPaks;
|
TWideStringList mPaks;
|
||||||
std::map<CAssetID, bool> mAreaDuplicateMap;
|
std::map<CAssetID, bool> mAreaDuplicateMap;
|
||||||
CAssetNameMap *mpNameMap;
|
CAssetNameMap mNameMap;
|
||||||
|
CGameInfo mGameInfo;
|
||||||
|
|
||||||
struct SResourceInstance
|
struct SResourceInstance
|
||||||
{
|
{
|
||||||
|
@ -50,6 +56,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CopyDiscData();
|
void CopyDiscData();
|
||||||
|
void FindBuildVersion();
|
||||||
void LoadPaks();
|
void LoadPaks();
|
||||||
void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer);
|
void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer);
|
||||||
void ExportCookedResources();
|
void ExportCookedResources();
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include "CGameInfo.h"
|
||||||
|
|
||||||
|
void CGameInfo::LoadGameInfo(EGame Game)
|
||||||
|
{
|
||||||
|
Game = RoundGame(Game);
|
||||||
|
mGame = Game;
|
||||||
|
|
||||||
|
LoadGameInfo(GetDefaultGameInfoPath(Game));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGameInfo::LoadGameInfo(TString Path)
|
||||||
|
{
|
||||||
|
CXMLReader Reader(Path);
|
||||||
|
Serialize(Reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
||||||
|
{
|
||||||
|
ASSERT(mGame != eUnknownGame); // can't save game info that was never loaded
|
||||||
|
|
||||||
|
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
|
||||||
|
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
|
||||||
|
Serialize(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGameInfo::Serialize(IArchive& rArc)
|
||||||
|
{
|
||||||
|
// Validate game
|
||||||
|
if (rArc.IsReader() && mGame != eUnknownGame)
|
||||||
|
{
|
||||||
|
ASSERT(mGame == rArc.Game());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize data
|
||||||
|
if (mGame <= ePrime)
|
||||||
|
rArc << SERIAL_CONTAINER("AreaNameMap", mAreaNameMap, "AreaName");
|
||||||
|
}
|
||||||
|
|
||||||
|
TString CGameInfo::GetAreaName(const CAssetID &rkID) const
|
||||||
|
{
|
||||||
|
auto Iter = mAreaNameMap.find(rkID);
|
||||||
|
return (Iter == mAreaNameMap.end() ? "" : Iter->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ STATIC ************
|
||||||
|
EGame CGameInfo::RoundGame(EGame Game)
|
||||||
|
{
|
||||||
|
if (Game == ePrimeDemo) return ePrime;
|
||||||
|
if (Game == eEchoesDemo) return eEchoes;
|
||||||
|
if (Game == eCorruptionProto) return eCorruption;
|
||||||
|
return Game;
|
||||||
|
}
|
||||||
|
|
||||||
|
TString CGameInfo::GetDefaultGameInfoPath(EGame Game)
|
||||||
|
{
|
||||||
|
Game = RoundGame(Game);
|
||||||
|
|
||||||
|
if (Game == eUnknownGame)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
TString GameName = GetGameShortName(Game);
|
||||||
|
return TString::Format("%s\\GameInfo%s.xml", *gkGameInfoDir, *GameName);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef CGAMEINFO
|
||||||
|
#define CGAMEINFO
|
||||||
|
|
||||||
|
#include <Common/AssertMacro.h>
|
||||||
|
#include <Common/CAssetID.h>
|
||||||
|
#include <Common/TString.h>
|
||||||
|
#include <Common/Serialization/IArchive.h>
|
||||||
|
#include <Common/Serialization/XML.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
const TString gkGameInfoDir = "..\\resources\\gameinfo";
|
||||||
|
|
||||||
|
class CGameInfo
|
||||||
|
{
|
||||||
|
EGame mGame;
|
||||||
|
std::map<CAssetID, TString> mAreaNameMap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CGameInfo()
|
||||||
|
: mGame(eUnknownGame)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void LoadGameInfo(EGame Game);
|
||||||
|
void LoadGameInfo(TString Path);
|
||||||
|
void SaveGameInfo(TString Path = "");
|
||||||
|
void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
|
TString GetAreaName(const CAssetID& rkID) const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline EGame Game() const { return mGame; }
|
||||||
|
|
||||||
|
// Static
|
||||||
|
static CGameInfo* GetGameInfo(EGame Game);
|
||||||
|
static EGame RoundGame(EGame Game);
|
||||||
|
static TString GetDefaultGameInfoPath(EGame Game);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CGAMEINFO
|
||||||
|
|
|
@ -13,6 +13,7 @@ CGameProject::~CGameProject()
|
||||||
mspActiveProject = nullptr;
|
mspActiveProject = nullptr;
|
||||||
|
|
||||||
delete mpAudioManager;
|
delete mpAudioManager;
|
||||||
|
delete mpGameInfo;
|
||||||
delete mpResourceStore;
|
delete mpResourceStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +24,12 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||||
|
|
||||||
TString ProjPath = rkPath.ToUTF8();
|
TString ProjPath = rkPath.ToUTF8();
|
||||||
CXMLReader Reader(ProjPath);
|
CXMLReader Reader(ProjPath);
|
||||||
|
mGame = Reader.Game();
|
||||||
Serialize(Reader);
|
Serialize(Reader);
|
||||||
CTemplateLoader::LoadGameTemplates(mGame);
|
CTemplateLoader::LoadGameTemplates(mGame);
|
||||||
|
|
||||||
mpResourceStore->LoadResourceDatabase();
|
mpResourceStore->LoadResourceDatabase();
|
||||||
|
mpGameInfo->LoadGameInfo(mGame);
|
||||||
mpAudioManager->LoadAssets();
|
mpAudioManager->LoadAssets();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +44,7 @@ void CGameProject::Save()
|
||||||
void CGameProject::Serialize(IArchive& rArc)
|
void CGameProject::Serialize(IArchive& rArc)
|
||||||
{
|
{
|
||||||
rArc << SERIAL("Name", mProjectName)
|
rArc << SERIAL("Name", mProjectName)
|
||||||
<< SERIAL("Game", mGame)
|
<< SERIAL("BuildVersion", mBuildVersion)
|
||||||
<< SERIAL("ResourceDB", mResourceDBPath);
|
<< SERIAL("ResourceDB", mResourceDBPath);
|
||||||
|
|
||||||
// Packages
|
// Packages
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CGAMEPROJECT_H
|
#ifndef CGAMEPROJECT_H
|
||||||
#define CGAMEPROJECT_H
|
#define CGAMEPROJECT_H
|
||||||
|
|
||||||
|
#include "CGameInfo.h"
|
||||||
#include "CPackage.h"
|
#include "CPackage.h"
|
||||||
#include "CResourceStore.h"
|
#include "CResourceStore.h"
|
||||||
#include "Core/CAudioManager.h"
|
#include "Core/CAudioManager.h"
|
||||||
|
@ -14,11 +15,13 @@
|
||||||
class CGameProject
|
class CGameProject
|
||||||
{
|
{
|
||||||
EGame mGame;
|
EGame mGame;
|
||||||
|
float mBuildVersion;
|
||||||
TString mProjectName;
|
TString mProjectName;
|
||||||
TWideString mProjectRoot;
|
TWideString mProjectRoot;
|
||||||
TWideString mResourceDBPath;
|
TWideString mResourceDBPath;
|
||||||
std::vector<CPackage*> mPackages;
|
std::vector<CPackage*> mPackages;
|
||||||
CResourceStore *mpResourceStore;
|
CResourceStore *mpResourceStore;
|
||||||
|
CGameInfo *mpGameInfo;
|
||||||
CAudioManager *mpAudioManager;
|
CAudioManager *mpAudioManager;
|
||||||
|
|
||||||
enum EProjectVersion
|
enum EProjectVersion
|
||||||
|
@ -38,6 +41,7 @@ public:
|
||||||
, mResourceDBPath(L"ResourceDB.rdb")
|
, mResourceDBPath(L"ResourceDB.rdb")
|
||||||
{
|
{
|
||||||
mpResourceStore = new CResourceStore(this);
|
mpResourceStore = new CResourceStore(this);
|
||||||
|
mpGameInfo = new CGameInfo();
|
||||||
mpAudioManager = new CAudioManager(this);
|
mpAudioManager = new CAudioManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,17 +53,21 @@ public:
|
||||||
{
|
{
|
||||||
mProjectRoot.Replace(L"/", L"\\");
|
mProjectRoot.Replace(L"/", L"\\");
|
||||||
mpResourceStore = new CResourceStore(this);
|
mpResourceStore = new CResourceStore(this);
|
||||||
|
mpGameInfo = new CGameInfo();
|
||||||
mpAudioManager = new CAudioManager(this);
|
mpAudioManager = new CAudioManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameProject(CGameExporter *pExporter, const TWideString& rkProjRootDir, EGame Game)
|
CGameProject(CGameExporter *pExporter, const TWideString& rkProjRootDir, EGame Game, float BuildVer)
|
||||||
: mGame(Game)
|
: mGame(Game)
|
||||||
|
, mBuildVersion(BuildVer)
|
||||||
, mProjectName(CMasterTemplate::FindGameName(Game))
|
, mProjectName(CMasterTemplate::FindGameName(Game))
|
||||||
, mProjectRoot(rkProjRootDir)
|
, mProjectRoot(rkProjRootDir)
|
||||||
, mResourceDBPath(L"ResourceDB.rdb")
|
, mResourceDBPath(L"ResourceDB.rdb")
|
||||||
{
|
{
|
||||||
mProjectRoot.Replace(L"/", L"\\");
|
mProjectRoot.Replace(L"/", L"\\");
|
||||||
mpResourceStore = new CResourceStore(this, pExporter, L"Content\\", L"Cooked\\", Game);
|
mpResourceStore = new CResourceStore(this, pExporter, L"Content\\", L"Cooked\\", Game);
|
||||||
|
mpGameInfo = new CGameInfo();
|
||||||
|
mpGameInfo->LoadGameInfo(mGame);
|
||||||
mpAudioManager = new CAudioManager(this);
|
mpAudioManager = new CAudioManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,8 +96,10 @@ public:
|
||||||
inline CPackage* PackageByIndex(u32 Index) const { return mPackages[Index]; }
|
inline CPackage* PackageByIndex(u32 Index) const { return mPackages[Index]; }
|
||||||
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); }
|
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); }
|
||||||
inline CResourceStore* ResourceStore() const { return mpResourceStore; }
|
inline CResourceStore* ResourceStore() const { return mpResourceStore; }
|
||||||
|
inline CGameInfo* GameInfo() const { return mpGameInfo; }
|
||||||
inline CAudioManager* AudioManager() const { return mpAudioManager; }
|
inline CAudioManager* AudioManager() const { return mpAudioManager; }
|
||||||
inline EGame Game() const { return mGame; }
|
inline EGame Game() const { return mGame; }
|
||||||
|
inline float BuildVersion() const { return mBuildVersion; }
|
||||||
inline bool IsActive() const { return mspActiveProject == this; }
|
inline bool IsActive() const { return mspActiveProject == this; }
|
||||||
|
|
||||||
static inline CGameProject* ActiveProject() { return mspActiveProject; }
|
static inline CGameProject* ActiveProject() { return mspActiveProject; }
|
||||||
|
|
|
@ -316,11 +316,14 @@ bool CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
|
||||||
TString NewCookedPath = CookedAssetPath();
|
TString NewCookedPath = CookedAssetPath();
|
||||||
TString NewRawPath = RawAssetPath();
|
TString NewRawPath = RawAssetPath();
|
||||||
|
|
||||||
|
Log::Write("MOVING RESOURCE: " + OldCookedPath + " --> " + NewCookedPath);
|
||||||
|
|
||||||
// If the old/new paths are the same then we should have already exited as CanMoveTo() should have returned false
|
// If the old/new paths are the same then we should have already exited as CanMoveTo() should have returned false
|
||||||
ASSERT(OldCookedPath != NewCookedPath && OldRawPath != NewRawPath);
|
ASSERT(OldCookedPath != NewCookedPath && OldRawPath != NewRawPath);
|
||||||
|
|
||||||
// The cooked/raw asset paths should not exist right now!!!
|
// The cooked/raw asset paths should not exist right now!!!
|
||||||
bool FSMoveSuccess = false;
|
bool FSMoveSuccess = false;
|
||||||
|
TString MoveFailReason;
|
||||||
|
|
||||||
if (!HasRawVersion() && !HasCookedVersion())
|
if (!HasRawVersion() && !HasCookedVersion())
|
||||||
{
|
{
|
||||||
|
@ -329,15 +332,30 @@ bool CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
|
||||||
if (FileUtil::Exists(OldRawPath))
|
if (FileUtil::Exists(OldRawPath))
|
||||||
{
|
{
|
||||||
FSMoveSuccess = FileUtil::CopyFile(OldRawPath, NewRawPath);
|
FSMoveSuccess = FileUtil::CopyFile(OldRawPath, NewRawPath);
|
||||||
if (!FSMoveSuccess) FileUtil::DeleteFile(NewRawPath);
|
|
||||||
|
if (!FSMoveSuccess)
|
||||||
|
{
|
||||||
|
FileUtil::DeleteFile(NewRawPath);
|
||||||
|
MoveFailReason = TString::Format("Failed to move raw file to new destination (%s --> %s)", *OldRawPath, *NewRawPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FSMoveSuccess && FileUtil::Exists(OldCookedPath))
|
if (FSMoveSuccess && FileUtil::Exists(OldCookedPath))
|
||||||
{
|
{
|
||||||
FSMoveSuccess = FileUtil::CopyFile(OldCookedPath, NewCookedPath);
|
FSMoveSuccess = FileUtil::CopyFile(OldCookedPath, NewCookedPath);
|
||||||
if (!FSMoveSuccess) FileUtil::DeleteFile(NewCookedPath);
|
|
||||||
|
if (!FSMoveSuccess)
|
||||||
|
{
|
||||||
|
FileUtil::DeleteFile(NewCookedPath);
|
||||||
|
MoveFailReason = TString::Format("Failed to move cooked file to new destination (%s --> %s)", *OldCookedPath, *NewCookedPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool HasRaw = HasRawVersion();
|
||||||
|
MoveFailReason = TString::Format("File already exists at %s asset destination (%s)", HasRaw ? "raw" : "cooked", HasRaw ? *NewRawPath : *NewCookedPath);
|
||||||
|
}
|
||||||
|
|
||||||
// If we succeeded, finish the move
|
// If we succeeded, finish the move
|
||||||
if (FSMoveSuccess)
|
if (FSMoveSuccess)
|
||||||
|
@ -360,6 +378,7 @@ bool CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
|
||||||
// Otherwise, revert changes and let the caller know the move failed
|
// Otherwise, revert changes and let the caller know the move failed
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Log::Error("MOVE FAILED: " + MoveFailReason);
|
||||||
mpDirectory = pOldDir;
|
mpDirectory = pOldDir;
|
||||||
mName = OldName;
|
mName = OldName;
|
||||||
mpStore->ConditionalDeleteDirectory(pNewDir);
|
mpStore->ConditionalDeleteDirectory(pNewDir);
|
||||||
|
|
|
@ -16,11 +16,10 @@ enum EResEntryFlag
|
||||||
{
|
{
|
||||||
eREF_NeedsRecook = 0x00000001, // Resource has been updated but not recooked
|
eREF_NeedsRecook = 0x00000001, // Resource has been updated but not recooked
|
||||||
eREF_Transient = 0x00000002, // Resource is transient (not part of a game project resource DB)
|
eREF_Transient = 0x00000002, // Resource is transient (not part of a game project resource DB)
|
||||||
eREF_HasThumbnail = 0x00000004, // Resource has a unique thumbnail
|
eREF_Hidden = 0x00000004, // Resource is hidden, doesn't show up in resource browser
|
||||||
eREF_ThumbnailLoaded = 0x00000008, // Resource thumbnail is currently in memory
|
eREF_HasBeenModified = 0x00000008, // Resource has been modified and resaved by the user
|
||||||
eREF_Hidden = 0x00000010, // Resource is hidden, doesn't show up in resource browser
|
|
||||||
// Flags that save to the cache file
|
// Flags that save to the cache file
|
||||||
eREF_SavedFlags = eREF_NeedsRecook | eREF_HasThumbnail | eREF_Hidden
|
eREF_SavedFlags = eREF_NeedsRecook | eREF_Hidden | eREF_HasBeenModified
|
||||||
};
|
};
|
||||||
DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
||||||
|
|
||||||
|
|
|
@ -323,7 +323,9 @@ void CResourceStore::ConditionalDeleteDirectory(CVirtualDirectory *pDir)
|
||||||
FileUtil::DeleteDirectory(CookedDir(false) + pDir->FullPath());
|
FileUtil::DeleteDirectory(CookedDir(false) + pDir->FullPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
pDir->Parent()->RemoveChildDirectory(pDir);
|
CVirtualDirectory *pParent = pDir->Parent();
|
||||||
|
pParent->RemoveChildDirectory(pDir);
|
||||||
|
ConditionalDeleteDirectory(pParent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,10 +160,6 @@ bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir)
|
||||||
{
|
{
|
||||||
mSubdirectories.erase(It);
|
mSubdirectories.erase(It);
|
||||||
delete pSubdir;
|
delete pSubdir;
|
||||||
|
|
||||||
if (mpParent && IsEmpty())
|
|
||||||
mpParent->RemoveChildDirectory(this);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CWorldLoader.h"
|
#include "CWorldLoader.h"
|
||||||
|
#include "Core/GameProject/CGameProject.h"
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "Core/GameProject/CResourceStore.h"
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
|
|
||||||
|
@ -125,11 +126,9 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal name - MP1 doesn't have this so reuse the area's real name
|
// Internal name - MP1 doesn't have this, we'll get it from the GameInfo file later
|
||||||
if (mVersion >= eEchoesDemo)
|
if (mVersion >= eEchoesDemo)
|
||||||
pArea->InternalName = rMLVL.ReadString();
|
pArea->InternalName = rMLVL.ReadString();
|
||||||
else
|
|
||||||
pArea->InternalName = (pArea->pAreaName ? pArea->pAreaName->String("ENGL", 0).ToUTF8() : "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapWorld
|
// MapWorld
|
||||||
|
@ -234,6 +233,21 @@ void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
|
||||||
// todo: Layer ID support
|
// todo: Layer ID support
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWorldLoader::GenerateEditorData()
|
||||||
|
{
|
||||||
|
CGameInfo *pGameInfo = mpWorld->Entry()->ResourceStore()->Project()->GameInfo();
|
||||||
|
|
||||||
|
if (mVersion <= ePrime)
|
||||||
|
{
|
||||||
|
for (u32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
|
||||||
|
{
|
||||||
|
CWorld::SArea& rArea = mpWorld->mAreas[iArea];
|
||||||
|
rArea.InternalName = pGameInfo->GetAreaName(rArea.AreaResID);
|
||||||
|
ASSERT(!rArea.InternalName.IsEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
|
CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
if (!rMLVL.IsValid()) return nullptr;
|
if (!rMLVL.IsValid()) return nullptr;
|
||||||
|
@ -264,6 +278,7 @@ CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
|
||||||
else
|
else
|
||||||
Loader.LoadReturnsMLVL(rMLVL);
|
Loader.LoadReturnsMLVL(rMLVL);
|
||||||
|
|
||||||
|
Loader.GenerateEditorData();
|
||||||
return Loader.mpWorld;
|
return Loader.mpWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class CWorldLoader
|
||||||
CWorldLoader();
|
CWorldLoader();
|
||||||
void LoadPrimeMLVL(IInputStream& rMLVL);
|
void LoadPrimeMLVL(IInputStream& rMLVL);
|
||||||
void LoadReturnsMLVL(IInputStream& rMLVL);
|
void LoadReturnsMLVL(IInputStream& rMLVL);
|
||||||
|
void GenerateEditorData();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CWorld* LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry);
|
static CWorld* LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry);
|
||||||
|
|
|
@ -275,6 +275,22 @@ bool CModel::IsSurfaceTransparent(u32 Surface, u32 MatSet)
|
||||||
return (mMaterialSets[MatSet]->MaterialByIndex(matID)->Options() & CMaterial::eTransparent) != 0;
|
return (mMaterialSets[MatSet]->MaterialByIndex(matID)->Options() & CMaterial::eTransparent) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CModel::IsLightmapped() const
|
||||||
|
{
|
||||||
|
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
|
||||||
|
{
|
||||||
|
CMaterialSet *pSet = mMaterialSets[iSet];
|
||||||
|
|
||||||
|
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
||||||
|
{
|
||||||
|
CMaterial *pMat = pSet->MaterialByIndex(iMat);
|
||||||
|
if (pMat->Options().HasFlag(CMaterial::eLightmap))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CIndexBuffer* CModel::InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive)
|
CIndexBuffer* CModel::InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive)
|
||||||
{
|
{
|
||||||
std::vector<CIndexBuffer> *pIBOs = &mSurfaceIndexBuffers[Surface];
|
std::vector<CIndexBuffer> *pIBOs = &mSurfaceIndexBuffers[Surface];
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
CMaterial* GetMaterialBySurface(u32 MatSet, u32 Surface);
|
CMaterial* GetMaterialBySurface(u32 MatSet, u32 Surface);
|
||||||
bool HasTransparency(u32 MatSet);
|
bool HasTransparency(u32 MatSet);
|
||||||
bool IsSurfaceTransparent(u32 Surface, u32 MatSet);
|
bool IsSurfaceTransparent(u32 Surface, u32 MatSet);
|
||||||
|
bool IsLightmapped() const;
|
||||||
|
|
||||||
inline bool IsSkinned() const { return (mpSkin != nullptr); }
|
inline bool IsSkinned() const { return (mpSkin != nullptr); }
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ void CEditorApplication::TickEditors()
|
||||||
// The resource store should NOT be dirty at the beginning of a tick - this indicates we forgot to save it after updating somewhere
|
// The resource store should NOT be dirty at the beginning of a tick - this indicates we forgot to save it after updating somewhere
|
||||||
if (gpResourceStore && gpResourceStore->IsDirty())
|
if (gpResourceStore && gpResourceStore->IsDirty())
|
||||||
{
|
{
|
||||||
Log::Error("ERROR: Resource store is dirty at the beginning of a tick! Call ConditionalSaveStore() after making any significant changes to assets!");
|
Log::Error("Resource store is dirty at the beginning of a tick! Call ConditionalSaveStore() after making any significant changes to assets!");
|
||||||
DEBUG_BREAK;
|
DEBUG_BREAK;
|
||||||
gpResourceStore->ConditionalSaveStore();
|
gpResourceStore->ConditionalSaveStore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "ui_CResourceBrowser.h"
|
#include "ui_CResourceBrowser.h"
|
||||||
#include "Editor/ModelEditor/CModelEditorWindow.h"
|
#include "Editor/ModelEditor/CModelEditorWindow.h"
|
||||||
#include "Editor/CharacterEditor/CCharacterEditor.h"
|
#include "Editor/CharacterEditor/CCharacterEditor.h"
|
||||||
|
#include <Core/GameProject/AssetNameGeneration.h>
|
||||||
|
#include <Core/GameProject/CAssetNameMap.h>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -38,6 +40,14 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
|
||||||
QAction *pImportFromContentsTxtAction = new QAction("Import from Pak Contents List", this);
|
QAction *pImportFromContentsTxtAction = new QAction("Import from Pak Contents List", this);
|
||||||
pImportNamesMenu->addAction(pImportFromContentsTxtAction);
|
pImportNamesMenu->addAction(pImportFromContentsTxtAction);
|
||||||
|
|
||||||
|
#if !PUBLIC_RELEASE
|
||||||
|
QAction *pGenerateAssetNamesAction = new QAction("Generate Asset Names", this);
|
||||||
|
pImportNamesMenu->addAction(pGenerateAssetNamesAction);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QAction *pImportFromAssetNameMapAction = new QAction("Import from Asset Name Map", this);
|
||||||
|
pImportNamesMenu->addAction(pImportFromAssetNameMapAction);
|
||||||
|
|
||||||
// Set up connections
|
// Set up connections
|
||||||
connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnStoreChanged(int)));
|
connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnStoreChanged(int)));
|
||||||
connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged()));
|
connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged()));
|
||||||
|
@ -45,7 +55,13 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
|
||||||
connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex)));
|
connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex)));
|
||||||
connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickResource(QModelIndex)));
|
connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickResource(QModelIndex)));
|
||||||
connect(pImportFromContentsTxtAction, SIGNAL(triggered()), this, SLOT(OnImportPakContentsTxt()));
|
connect(pImportFromContentsTxtAction, SIGNAL(triggered()), this, SLOT(OnImportPakContentsTxt()));
|
||||||
|
connect(pImportFromAssetNameMapAction, SIGNAL(triggered()), this, SLOT(OnImportNamesFromAssetNameMap()));
|
||||||
|
connect(mpUI->ExportNamesButton, SIGNAL(clicked()), this, SLOT(ExportAssetNames()));
|
||||||
connect(&mUpdateFilterTimer, SIGNAL(timeout()), this, SLOT(UpdateFilter()));
|
connect(&mUpdateFilterTimer, SIGNAL(timeout()), this, SLOT(UpdateFilter()));
|
||||||
|
|
||||||
|
#if !PUBLIC_RELEASE
|
||||||
|
connect(pGenerateAssetNamesAction, SIGNAL(triggered()), this, SLOT(OnGenerateAssetNames()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceBrowser::~CResourceBrowser()
|
CResourceBrowser::~CResourceBrowser()
|
||||||
|
@ -142,6 +158,40 @@ void CResourceBrowser::OnImportPakContentsTxt()
|
||||||
RefreshResources();
|
RefreshResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::OnGenerateAssetNames()
|
||||||
|
{
|
||||||
|
GenerateAssetNames(mpStore->Project());
|
||||||
|
RefreshResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::OnImportNamesFromAssetNameMap()
|
||||||
|
{
|
||||||
|
CAssetNameMap Map;
|
||||||
|
Map.LoadAssetNames();
|
||||||
|
|
||||||
|
for (CResourceIterator It(mpStore); It; ++It)
|
||||||
|
{
|
||||||
|
TString Dir, Name;
|
||||||
|
|
||||||
|
if (Map.GetNameInfo(It->ID(), Dir, Name))
|
||||||
|
It->Move(Dir.ToUTF16(), Name.ToUTF16());
|
||||||
|
}
|
||||||
|
|
||||||
|
mpStore->ConditionalSaveStore();
|
||||||
|
RefreshResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::ExportAssetNames()
|
||||||
|
{
|
||||||
|
QString OutFile = QFileDialog::getSaveFileName(this, "Export asset name map", "../resources/gameinfo/", "*.xml");
|
||||||
|
if (OutFile.isEmpty()) return;
|
||||||
|
|
||||||
|
CAssetNameMap NameMap;
|
||||||
|
NameMap.LoadAssetNames();
|
||||||
|
NameMap.CopyFromStore(mpStore);
|
||||||
|
NameMap.SaveAssetNames();
|
||||||
|
}
|
||||||
|
|
||||||
void CResourceBrowser::UpdateFilter()
|
void CResourceBrowser::UpdateFilter()
|
||||||
{
|
{
|
||||||
mpProxyModel->SetSearchString( TO_TWIDESTRING(mpUI->SearchBar->text()) );
|
mpProxyModel->SetSearchString( TO_TWIDESTRING(mpUI->SearchBar->text()) );
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "CResourceTableModel.h"
|
#include "CResourceTableModel.h"
|
||||||
#include "CVirtualDirectoryModel.h"
|
#include "CVirtualDirectoryModel.h"
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class CResourceBrowser;
|
class CResourceBrowser;
|
||||||
|
@ -32,6 +33,9 @@ public slots:
|
||||||
void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex);
|
void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex);
|
||||||
void OnDoubleClickResource(QModelIndex Index);
|
void OnDoubleClickResource(QModelIndex Index);
|
||||||
void OnImportPakContentsTxt();
|
void OnImportPakContentsTxt();
|
||||||
|
void OnGenerateAssetNames();
|
||||||
|
void OnImportNamesFromAssetNameMap();
|
||||||
|
void ExportAssetNames();
|
||||||
void UpdateFilter();
|
void UpdateFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue