Added progress bars for most major blocking operations
This commit is contained in:
parent
31621874a6
commit
0a9b052413
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
class CFourCC
|
class CFourCC
|
||||||
{
|
{
|
||||||
// Note: mFourCC_Chars isn't really used due to endian issues. It's mostly here for easier readability in the debugger.
|
// Note: mFourCC_Chars isn't used much due to endianness.
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
u32 mFourCC;
|
u32 mFourCC;
|
||||||
|
|
|
@ -227,7 +227,8 @@ HEADERS += \
|
||||||
CompressionUtil.h \
|
CompressionUtil.h \
|
||||||
Resource/Animation/CSourceAnimData.h \
|
Resource/Animation/CSourceAnimData.h \
|
||||||
Resource/CMapArea.h \
|
Resource/CMapArea.h \
|
||||||
Resource/CSavedStateID.h
|
Resource/CSavedStateID.h \
|
||||||
|
IProgressNotifier.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
|
|
@ -23,6 +23,7 @@ CGameExporter::CGameExporter(EGame Game, ERegion Region, const TString& rkGameNa
|
||||||
, mGameName(rkGameName)
|
, mGameName(rkGameName)
|
||||||
, mGameID(rkGameID)
|
, mGameID(rkGameID)
|
||||||
, mBuildVersion(BuildVersion)
|
, mBuildVersion(BuildVersion)
|
||||||
|
, mpProgress(nullptr)
|
||||||
{
|
{
|
||||||
ASSERT(mGame != eUnknownGame);
|
ASSERT(mGame != eUnknownGame);
|
||||||
ASSERT(mRegion != eRegion_Unknown);
|
ASSERT(mRegion != eRegion_Unknown);
|
||||||
|
@ -32,7 +33,7 @@ CGameExporter::CGameExporter(EGame Game, ERegion Region, const TString& rkGameNa
|
||||||
#error Fix export directory being cleared!
|
#error Fix export directory being cleared!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo)
|
bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
SCOPED_TIMER(ExportGame);
|
SCOPED_TIMER(ExportGame);
|
||||||
|
|
||||||
|
@ -44,6 +45,10 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs
|
||||||
mDiscDir = "Disc/";
|
mDiscDir = "Disc/";
|
||||||
mWorldsDirName = "Worlds/";
|
mWorldsDirName = "Worlds/";
|
||||||
|
|
||||||
|
// Init progress
|
||||||
|
mpProgress = pProgress;
|
||||||
|
mpProgress->SetNumTasks(eES_NumSteps);
|
||||||
|
|
||||||
// Create project
|
// Create project
|
||||||
FileUtil::MakeDirectory(mExportDir);
|
FileUtil::MakeDirectory(mExportDir);
|
||||||
FileUtil::ClearDirectory(mExportDir);
|
FileUtil::ClearDirectory(mExportDir);
|
||||||
|
@ -72,17 +77,22 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs
|
||||||
CResourceStore *pOldStore = gpResourceStore;
|
CResourceStore *pOldStore = gpResourceStore;
|
||||||
gpResourceStore = mpStore;
|
gpResourceStore = mpStore;
|
||||||
|
|
||||||
// Export game data
|
// Export cooked data
|
||||||
LoadPaks();
|
LoadPaks();
|
||||||
ExportCookedResources();
|
ExportCookedResources();
|
||||||
mpProject->AudioManager()->LoadAssets();
|
|
||||||
ExportResourceEditorData();
|
// Export editor data
|
||||||
|
if (!mpProgress->ShouldCancel())
|
||||||
|
{
|
||||||
|
mpProject->AudioManager()->LoadAssets();
|
||||||
|
ExportResourceEditorData();
|
||||||
|
}
|
||||||
|
|
||||||
// Export finished!
|
// Export finished!
|
||||||
mProjectPath = mpProject->ProjectPath();
|
mProjectPath = mpProject->ProjectPath();
|
||||||
delete mpProject;
|
delete mpProject;
|
||||||
if (pOldStore) gpResourceStore = pOldStore;
|
if (pOldStore) gpResourceStore = pOldStore;
|
||||||
return true;
|
return !mpProgress->ShouldCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer)
|
void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer)
|
||||||
|
@ -97,6 +107,9 @@ bool CGameExporter::ExtractDiscData()
|
||||||
// todo: handle dol, apploader, multiple partitions, wii ticket blob
|
// todo: handle dol, apploader, multiple partitions, wii ticket blob
|
||||||
SCOPED_TIMER(ExtractDiscData);
|
SCOPED_TIMER(ExtractDiscData);
|
||||||
|
|
||||||
|
// Init progress
|
||||||
|
mpProgress->SetTask(eES_ExtractDisc, "Extracting disc files");
|
||||||
|
|
||||||
// Create Disc output folder
|
// Create Disc output folder
|
||||||
TString AbsDiscDir = mExportDir + mDiscDir;
|
TString AbsDiscDir = mExportDir + mDiscDir;
|
||||||
FileUtil::MakeDirectory(AbsDiscDir);
|
FileUtil::MakeDirectory(AbsDiscDir);
|
||||||
|
@ -106,43 +119,52 @@ bool CGameExporter::ExtractDiscData()
|
||||||
nod::ExtractionContext Context;
|
nod::ExtractionContext Context;
|
||||||
Context.force = false;
|
Context.force = false;
|
||||||
Context.verbose = false;
|
Context.verbose = false;
|
||||||
Context.progressCB = nullptr;
|
Context.progressCB = [&](const std::string& rkDesc) {
|
||||||
|
mpProgress->Report(0, 1, rkDesc);
|
||||||
|
};
|
||||||
|
|
||||||
bool Success = ExtractDiscNodeRecursive(&pDataPartition->getFSTRoot(), AbsDiscDir, Context);
|
bool Success = ExtractDiscNodeRecursive(&pDataPartition->getFSTRoot(), AbsDiscDir, Context);
|
||||||
if (!Success) return false;
|
if (!Success) return false;
|
||||||
|
|
||||||
// Extract dol
|
// Extract the remaining disc data
|
||||||
mDolPath = "boot.dol";
|
if (!mpProgress->ShouldCancel())
|
||||||
CFileOutStream DolFile(mExportDir + mDolPath);
|
|
||||||
if (!DolFile.IsValid()) return false;
|
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> pDolBuffer = pDataPartition->getDOLBuf();
|
|
||||||
DolFile.WriteBytes(pDolBuffer.get(), (u32) pDataPartition->getDOLSize());
|
|
||||||
DolFile.Close();
|
|
||||||
|
|
||||||
// Extract apploader
|
|
||||||
mApploaderPath = "apploader.img";
|
|
||||||
CFileOutStream ApploaderFile(mExportDir + mApploaderPath);
|
|
||||||
if (!ApploaderFile.IsValid()) return false;
|
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> pApploaderBuffer = pDataPartition->getApploaderBuf();
|
|
||||||
ApploaderFile.WriteBytes(pApploaderBuffer.get(), (u32) pDataPartition->getApploaderSize());
|
|
||||||
ApploaderFile.Close();
|
|
||||||
|
|
||||||
// Extract Wii partition header
|
|
||||||
bool IsWii = (mBuildVersion >= 3.f);
|
|
||||||
|
|
||||||
if (IsWii)
|
|
||||||
{
|
{
|
||||||
mFilesystemAddress = 0;
|
// Extract dol
|
||||||
mPartitionHeaderPath = "partition_header.bin";
|
mDolPath = "boot.dol";
|
||||||
nod::DiscWii *pDiscWii = static_cast<nod::DiscWii*>(mpDisc);
|
CFileOutStream DolFile(mExportDir + mDolPath);
|
||||||
Success = pDiscWii->writeOutDataPartitionHeader(*TString(mExportDir + mPartitionHeaderPath).ToUTF16());
|
if (!DolFile.IsValid()) return false;
|
||||||
if (!Success) return false;
|
|
||||||
|
std::unique_ptr<uint8_t[]> pDolBuffer = pDataPartition->getDOLBuf();
|
||||||
|
DolFile.WriteBytes(pDolBuffer.get(), (u32) pDataPartition->getDOLSize());
|
||||||
|
DolFile.Close();
|
||||||
|
|
||||||
|
// Extract apploader
|
||||||
|
mApploaderPath = "apploader.img";
|
||||||
|
CFileOutStream ApploaderFile(mExportDir + mApploaderPath);
|
||||||
|
if (!ApploaderFile.IsValid()) return false;
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]> pApploaderBuffer = pDataPartition->getApploaderBuf();
|
||||||
|
ApploaderFile.WriteBytes(pApploaderBuffer.get(), (u32) pDataPartition->getApploaderSize());
|
||||||
|
ApploaderFile.Close();
|
||||||
|
|
||||||
|
// Extract Wii partition header
|
||||||
|
bool IsWii = (mBuildVersion >= 3.f);
|
||||||
|
|
||||||
|
if (IsWii)
|
||||||
|
{
|
||||||
|
mFilesystemAddress = 0;
|
||||||
|
mPartitionHeaderPath = "partition_header.bin";
|
||||||
|
nod::DiscWii *pDiscWii = static_cast<nod::DiscWii*>(mpDisc);
|
||||||
|
Success = pDiscWii->writeOutDataPartitionHeader(*TString(mExportDir + mPartitionHeaderPath).ToUTF16());
|
||||||
|
if (!Success) return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mFilesystemAddress = (u32) pDataPartition->getFSTMemoryAddr();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mFilesystemAddress = (u32) pDataPartition->getFSTMemoryAddr();
|
return false;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, const nod::ExtractionContext& rkContext)
|
bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TString& rkDir, const nod::ExtractionContext& rkContext)
|
||||||
|
@ -447,9 +469,18 @@ void CGameExporter::ExportCookedResources()
|
||||||
SCOPED_TIMER(ExportCookedResources);
|
SCOPED_TIMER(ExportCookedResources);
|
||||||
FileUtil::MakeDirectory(mCookedDir);
|
FileUtil::MakeDirectory(mCookedDir);
|
||||||
|
|
||||||
for (auto It = mResourceMap.begin(); It != mResourceMap.end(); It++)
|
mpProgress->SetTask(eES_ExportCooked, "Unpacking cooked assets");
|
||||||
|
int ResIndex = 0;
|
||||||
|
|
||||||
|
for (auto It = mResourceMap.begin(); It != mResourceMap.end() && !mpProgress->ShouldCancel(); It++, ResIndex++)
|
||||||
{
|
{
|
||||||
SResourceInstance& rRes = It->second;
|
SResourceInstance& rRes = It->second;
|
||||||
|
|
||||||
|
// Update progress
|
||||||
|
if ((ResIndex & 0x3) == 0)
|
||||||
|
mpProgress->Report(ResIndex, mResourceMap.size(), TString::Format("Unpacking asset %d/%d", ResIndex, mResourceMap.size()) );
|
||||||
|
|
||||||
|
// Export resource
|
||||||
ExportResource(rRes);
|
ExportResource(rRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,12 +493,19 @@ void CGameExporter::ExportResourceEditorData()
|
||||||
// because we have to load the resource to build its dependency tree and
|
// because we have to load the resource to build its dependency tree and
|
||||||
// some resources will fail to load if their dependencies don't exist
|
// some resources will fail to load if their dependencies don't exist
|
||||||
SCOPED_TIMER(SaveRawResources);
|
SCOPED_TIMER(SaveRawResources);
|
||||||
|
mpProgress->SetTask(eES_GenerateRaw, "Generating editor data");
|
||||||
|
int ResIndex = 0;
|
||||||
|
|
||||||
// todo: we're wasting a ton of time loading the same resources over and over because most resources automatically
|
// todo: we're wasting a ton of time loading the same resources over and over because most resources automatically
|
||||||
// load all their dependencies and then we just clear it out from memory even though we'll need it again later. we
|
// load all their dependencies and then we just clear it out from memory even though we'll need it again later. we
|
||||||
// should really be doing this by dependency order instead of by ID order.
|
// should really be doing this by dependency order instead of by ID order.
|
||||||
for (CResourceIterator It(mpStore); It; ++It)
|
for (CResourceIterator It(mpStore); It && !mpProgress->ShouldCancel(); ++It, ++ResIndex)
|
||||||
{
|
{
|
||||||
|
// Update progress
|
||||||
|
if ((ResIndex & 0x3) == 0)
|
||||||
|
mpProgress->Report(ResIndex, mpStore->NumTotalResources(), TString::Format("Processing asset %d/%d: %s",
|
||||||
|
ResIndex, mpStore->NumTotalResources(), *It->CookedAssetPath(true).GetFileName()) );
|
||||||
|
|
||||||
// Worlds need some info we can only get from the pak at export time; namely, which areas can
|
// Worlds need some info we can only get from the pak at export time; namely, which areas can
|
||||||
// have duplicates, as well as the world's internal name.
|
// have duplicates, as well as the world's internal name.
|
||||||
if (It->ResourceType() == eWorld)
|
if (It->ResourceType() == eWorld)
|
||||||
|
@ -496,6 +534,8 @@ void CGameExporter::ExportResourceEditorData()
|
||||||
It->UpdateDependencies();
|
It->UpdateDependencies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mpProgress->ShouldCancel())
|
||||||
{
|
{
|
||||||
// All resources should have dependencies generated, so save the project files
|
// All resources should have dependencies generated, so save the project files
|
||||||
SCOPED_TIMER(SaveResourceDatabase);
|
SCOPED_TIMER(SaveResourceDatabase);
|
||||||
|
|
|
@ -57,9 +57,21 @@ class CGameExporter
|
||||||
};
|
};
|
||||||
std::map<CAssetID, SResourceInstance> mResourceMap;
|
std::map<CAssetID, SResourceInstance> mResourceMap;
|
||||||
|
|
||||||
|
// Progress
|
||||||
|
IProgressNotifier *mpProgress;
|
||||||
|
|
||||||
|
enum EExportStep
|
||||||
|
{
|
||||||
|
eES_ExtractDisc,
|
||||||
|
eES_ExportCooked,
|
||||||
|
eES_GenerateRaw,
|
||||||
|
// eES_Max must be last
|
||||||
|
eES_NumSteps
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGameExporter(EGame Game, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
|
CGameExporter(EGame Game, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
|
||||||
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo);
|
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress);
|
||||||
void LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer);
|
void LoadResource(const CAssetID& rkID, std::vector<u8>& rBuffer);
|
||||||
|
|
||||||
inline TString ProjectPath() const { return mProjectPath; }
|
inline TString ProjectPath() const { return mProjectPath; }
|
||||||
|
|
|
@ -95,9 +95,7 @@ void CGameProject::Serialize(IArchive& rArc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressDummy(size_t, const nod::SystemString&, size_t) {}
|
bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress)
|
||||||
|
|
||||||
bool CGameProject::BuildISO(const TString& rkIsoPath)
|
|
||||||
{
|
{
|
||||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
||||||
|
|
||||||
|
@ -109,7 +107,13 @@ bool CGameProject::BuildISO(const TString& rkIsoPath)
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nod::DiscBuilderGCN *pBuilder = new nod::DiscBuilderGCN(*rkIsoPath.ToUTF16(), *mGameID, *mProjectName, mFilesystemAddress, &ProgressDummy);
|
auto ProgressCallback = [&](size_t, const nod::SystemString& rkInfoString, size_t)
|
||||||
|
{
|
||||||
|
pProgress->Report(0, 0, TWideString(rkInfoString).ToUTF8());
|
||||||
|
};
|
||||||
|
|
||||||
|
nod::DiscBuilderGCN *pBuilder = new nod::DiscBuilderGCN(*rkIsoPath.ToUTF16(), *mGameID, *mProjectName, mFilesystemAddress, ProgressCallback);
|
||||||
|
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
||||||
|
|
||||||
TWideString ProjRoot = ProjectRoot().ToUTF16();
|
TWideString ProjRoot = ProjectRoot().ToUTF16();
|
||||||
TWideString DiscRoot = DiscDir(false).ToUTF16();
|
TWideString DiscRoot = DiscDir(false).ToUTF16();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "CPackage.h"
|
#include "CPackage.h"
|
||||||
#include "CResourceStore.h"
|
#include "CResourceStore.h"
|
||||||
#include "Core/CAudioManager.h"
|
#include "Core/CAudioManager.h"
|
||||||
|
#include "Core/IProgressNotifier.h"
|
||||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||||
#include <Common/CAssetID.h>
|
#include <Common/CAssetID.h>
|
||||||
#include <Common/EGame.h>
|
#include <Common/EGame.h>
|
||||||
|
@ -65,7 +66,7 @@ public:
|
||||||
|
|
||||||
bool Save();
|
bool Save();
|
||||||
void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc);
|
||||||
bool BuildISO(const TString& rkIsoPath);
|
bool BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress);
|
||||||
void GetWorldList(std::list<CAssetID>& rOut) const;
|
void GetWorldList(std::list<CAssetID>& rOut) const;
|
||||||
CAssetID FindNamedResource(const TString& rkName) const;
|
CAssetID FindNamedResource(const TString& rkName) const;
|
||||||
CPackage* FindPackage(const TString& rkName) const;
|
CPackage* FindPackage(const TString& rkName) const;
|
||||||
|
|
|
@ -59,9 +59,13 @@ void CPackage::UpdateDependencyCache() const
|
||||||
mCacheDirty = false;
|
mCacheDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPackage::Cook()
|
void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
|
SCOPED_TIMER(CookPackage);
|
||||||
|
|
||||||
// Build asset list
|
// Build asset list
|
||||||
|
pProgress->Report(-1, -1, "Building dependency list");
|
||||||
|
|
||||||
CPackageDependencyListBuilder Builder(this);
|
CPackageDependencyListBuilder Builder(this);
|
||||||
std::list<CAssetID> AssetList;
|
std::list<CAssetID> AssetList;
|
||||||
Builder.BuildDependencyList(true, AssetList);
|
Builder.BuildDependencyList(true, AssetList);
|
||||||
|
@ -161,7 +165,7 @@ void CPackage::Cook()
|
||||||
u32 ResIdx = 0;
|
u32 ResIdx = 0;
|
||||||
u32 ResDataOffset = Pak.Tell();
|
u32 ResDataOffset = Pak.Tell();
|
||||||
|
|
||||||
for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++, ResIdx++)
|
for (auto Iter = AssetList.begin(); Iter != AssetList.end() && !pProgress->ShouldCancel(); Iter++, ResIdx++)
|
||||||
{
|
{
|
||||||
// Initialize entry, recook assets if needed
|
// Initialize entry, recook assets if needed
|
||||||
u32 AssetOffset = Pak.Tell();
|
u32 AssetOffset = Pak.Tell();
|
||||||
|
@ -170,8 +174,18 @@ void CPackage::Cook()
|
||||||
ASSERT(pEntry != nullptr);
|
ASSERT(pEntry != nullptr);
|
||||||
|
|
||||||
if (pEntry->NeedsRecook())
|
if (pEntry->NeedsRecook())
|
||||||
|
{
|
||||||
|
pProgress->Report(ResIdx, AssetList.size(), "Cooking asset: " + pEntry->Name() + "." + pEntry->CookedExtension());
|
||||||
pEntry->Cook();
|
pEntry->Cook();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
if (ResIdx & 0x1 || ResIdx == AssetList.size() - 1)
|
||||||
|
{
|
||||||
|
pProgress->Report(ResIdx, AssetList.size(), TString::Format("Writing asset %d/%d: %s", ResIdx+1, AssetList.size(), *(pEntry->Name() + "." + pEntry->CookedExtension())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update table info
|
||||||
SResourceTableInfo& rTableInfo = ResourceTableData[ResIdx];
|
SResourceTableInfo& rTableInfo = ResourceTableData[ResIdx];
|
||||||
rTableInfo.pEntry = pEntry;
|
rTableInfo.pEntry = pEntry;
|
||||||
rTableInfo.Offset = (Game <= eEchoes ? AssetOffset : AssetOffset - ResDataOffset);
|
rTableInfo.Offset = (Game <= eEchoes ? AssetOffset : AssetOffset - ResDataOffset);
|
||||||
|
@ -267,40 +281,51 @@ void CPackage::Cook()
|
||||||
}
|
}
|
||||||
ResDataSize = Pak.Tell() - ResDataOffset;
|
ResDataSize = Pak.Tell() - ResDataOffset;
|
||||||
|
|
||||||
// Write table of contents for real
|
// If we cancelled, don't finish writing the pak; delete the file instead and make sure the package is flagged for recook
|
||||||
if (Game >= eCorruption)
|
if (pProgress->ShouldCancel())
|
||||||
{
|
{
|
||||||
Pak.Seek(TocOffset, SEEK_SET);
|
Pak.Close();
|
||||||
Pak.WriteLong(3); // Always 3 pak sections
|
FileUtil::DeleteFile(PakPath);
|
||||||
Pak.WriteFourCC( FOURCC('STRG') );
|
mNeedsRecook = true;
|
||||||
Pak.WriteLong(NamesSize);
|
|
||||||
Pak.WriteFourCC( FOURCC('RSHD') );
|
|
||||||
Pak.WriteLong(ResTableSize);
|
|
||||||
Pak.WriteFourCC( FOURCC('DATA') );
|
|
||||||
Pak.WriteLong(ResDataSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write resource table for real
|
else
|
||||||
Pak.Seek(ResTableOffset+4, SEEK_SET);
|
|
||||||
|
|
||||||
for (u32 iRes = 0; iRes < AssetList.size(); iRes++)
|
|
||||||
{
|
{
|
||||||
const SResourceTableInfo& rkInfo = ResourceTableData[iRes];
|
// Write table of contents for real
|
||||||
CResourceEntry *pEntry = rkInfo.pEntry;
|
if (Game >= eCorruption)
|
||||||
|
{
|
||||||
|
Pak.Seek(TocOffset, SEEK_SET);
|
||||||
|
Pak.WriteLong(3); // Always 3 pak sections
|
||||||
|
Pak.WriteFourCC( FOURCC('STRG') );
|
||||||
|
Pak.WriteLong(NamesSize);
|
||||||
|
Pak.WriteFourCC( FOURCC('RSHD') );
|
||||||
|
Pak.WriteLong(ResTableSize);
|
||||||
|
Pak.WriteFourCC( FOURCC('DATA') );
|
||||||
|
Pak.WriteLong(ResDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
Pak.WriteLong( rkInfo.Compressed ? 1 : 0 );
|
// Write resource table for real
|
||||||
pEntry->CookedExtension().Write(Pak);
|
Pak.Seek(ResTableOffset+4, SEEK_SET);
|
||||||
pEntry->ID().Write(Pak);
|
|
||||||
Pak.WriteLong(rkInfo.Size);
|
for (u32 iRes = 0; iRes < AssetList.size(); iRes++)
|
||||||
Pak.WriteLong(rkInfo.Offset);
|
{
|
||||||
|
const SResourceTableInfo& rkInfo = ResourceTableData[iRes];
|
||||||
|
CResourceEntry *pEntry = rkInfo.pEntry;
|
||||||
|
|
||||||
|
Pak.WriteLong( rkInfo.Compressed ? 1 : 0 );
|
||||||
|
pEntry->CookedExtension().Write(Pak);
|
||||||
|
pEntry->ID().Write(Pak);
|
||||||
|
Pak.WriteLong(rkInfo.Size);
|
||||||
|
Pak.WriteLong(rkInfo.Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear recook flag
|
||||||
|
mNeedsRecook = false;
|
||||||
|
Log::Write("Finished writing " + PakPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear recook flag
|
|
||||||
mNeedsRecook = false;
|
|
||||||
Save();
|
Save();
|
||||||
|
|
||||||
Log::Write("Finished writing " + PakPath);
|
|
||||||
|
|
||||||
// Update resource store in case we recooked any assets
|
// Update resource store in case we recooked any assets
|
||||||
mpProject->ResourceStore()->ConditionalSaveStore();
|
mpProject->ResourceStore()->ConditionalSaveStore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <Common/CFourCC.h>
|
#include <Common/CFourCC.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <Common/Serialization/IArchive.h>
|
#include <Common/Serialization/IArchive.h>
|
||||||
|
#include "Core/IProgressNotifier.h"
|
||||||
|
|
||||||
class CGameProject;
|
class CGameProject;
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ public:
|
||||||
void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType);
|
void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType);
|
||||||
void UpdateDependencyCache() const;
|
void UpdateDependencyCache() const;
|
||||||
|
|
||||||
void Cook();
|
void Cook(IProgressNotifier *pProgress);
|
||||||
void CompareOriginalAssetList(const std::list<CAssetID>& rkNewList);
|
void CompareOriginalAssetList(const std::list<CAssetID>& rkNewList);
|
||||||
bool ContainsAsset(const CAssetID& rkID) const;
|
bool ContainsAsset(const CAssetID& rkID) const;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef IPROGRESSNOTIFIER_H
|
||||||
|
#define IPROGRESSNOTIFIER_H
|
||||||
|
|
||||||
|
#include <Common/Common.h>
|
||||||
|
|
||||||
|
class IProgressNotifier
|
||||||
|
{
|
||||||
|
TString mTaskName;
|
||||||
|
int mTaskIndex;
|
||||||
|
int mTaskCount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IProgressNotifier()
|
||||||
|
: mTaskIndex(0)
|
||||||
|
, mTaskCount(1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetNumTasks(int NumTasks)
|
||||||
|
{
|
||||||
|
mTaskName = "";
|
||||||
|
mTaskIndex = 0;
|
||||||
|
mTaskCount = NumTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTask(int TaskIndex, TString TaskName)
|
||||||
|
{
|
||||||
|
mTaskName = TaskName;
|
||||||
|
mTaskIndex = TaskIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Report(int StepIndex, int StepCount, const TString& rkStepDesc)
|
||||||
|
{
|
||||||
|
ASSERT(mTaskCount >= 1);
|
||||||
|
|
||||||
|
// Calculate percentage
|
||||||
|
float TaskPercent = 1.f / (float) mTaskCount;
|
||||||
|
float StepPercent = (StepCount >= 0 ? (float) StepIndex / (float) StepCount : 0.f);
|
||||||
|
float ProgressPercent = (TaskPercent * mTaskIndex) + (TaskPercent * StepPercent);
|
||||||
|
UpdateProgress(mTaskName, rkStepDesc, ProgressPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool ShouldCancel() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void UpdateProgress(const TString& rkTaskName, const TString& rkStepDesc, float ProgressPercent) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IPROGRESSNOTIFIER_H
|
|
@ -1,6 +1,7 @@
|
||||||
#include "CEditorApplication.h"
|
#include "CEditorApplication.h"
|
||||||
#include "IEditor.h"
|
#include "IEditor.h"
|
||||||
#include "CBasicViewport.h"
|
#include "CBasicViewport.h"
|
||||||
|
#include "CProgressDialog.h"
|
||||||
#include "CProjectSettingsDialog.h"
|
#include "CProjectSettingsDialog.h"
|
||||||
#include "Editor/CharacterEditor/CCharacterEditor.h"
|
#include "Editor/CharacterEditor/CCharacterEditor.h"
|
||||||
#include "Editor/ModelEditor/CModelEditorWindow.h"
|
#include "Editor/ModelEditor/CModelEditorWindow.h"
|
||||||
|
@ -9,7 +10,9 @@
|
||||||
#include <Common/AssertMacro.h>
|
#include <Common/AssertMacro.h>
|
||||||
#include <Common/CTimer.h>
|
#include <Common/CTimer.h>
|
||||||
#include <Core/GameProject/CGameProject.h>
|
#include <Core/GameProject/CGameProject.h>
|
||||||
#include <QMessageBox>
|
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
CEditorApplication::CEditorApplication(int& rArgc, char **ppArgv)
|
CEditorApplication::CEditorApplication(int& rArgc, char **ppArgv)
|
||||||
: QApplication(rArgc, ppArgv)
|
: QApplication(rArgc, ppArgv)
|
||||||
|
@ -141,19 +144,51 @@ void CEditorApplication::NotifyAssetsModified()
|
||||||
emit AssetsModified();
|
emit AssetsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEditorApplication::CookAllDirtyPackages()
|
bool CEditorApplication::CookPackage(CPackage *pPkg)
|
||||||
|
{
|
||||||
|
return CookPackageList(QList<CPackage*>() << pPkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditorApplication::CookAllDirtyPackages()
|
||||||
{
|
{
|
||||||
ASSERT(mpActiveProject != nullptr);
|
ASSERT(mpActiveProject != nullptr);
|
||||||
|
QList<CPackage*> PackageList;
|
||||||
|
|
||||||
for (u32 iPkg = 0; iPkg < mpActiveProject->NumPackages(); iPkg++)
|
for (u32 iPkg = 0; iPkg < mpActiveProject->NumPackages(); iPkg++)
|
||||||
{
|
{
|
||||||
CPackage *pPackage = mpActiveProject->PackageByIndex(iPkg);
|
CPackage *pPackage = mpActiveProject->PackageByIndex(iPkg);
|
||||||
|
|
||||||
if (pPackage->NeedsRecook())
|
if (pPackage->NeedsRecook())
|
||||||
pPackage->Cook();
|
PackageList << pPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit PackagesCooked();
|
return CookPackageList(PackageList);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditorApplication::CookPackageList(QList<CPackage*> PackageList)
|
||||||
|
{
|
||||||
|
if (!PackageList.isEmpty())
|
||||||
|
{
|
||||||
|
CProgressDialog Dialog("Cooking package" + QString(PackageList.size() > 1 ? "s" : ""), true, mpWorldEditor);
|
||||||
|
|
||||||
|
QFuture<void> Future = QtConcurrent::run([&]()
|
||||||
|
{
|
||||||
|
Dialog.SetNumTasks(PackageList.size());
|
||||||
|
|
||||||
|
for (int PkgIdx = 0; PkgIdx < PackageList.size() && !Dialog.ShouldCancel(); PkgIdx++)
|
||||||
|
{
|
||||||
|
CPackage *pPkg = PackageList[PkgIdx];
|
||||||
|
Dialog.SetTask(PkgIdx, "Cooking " + pPkg->Name() + ".pak...");
|
||||||
|
pPkg->Cook(&Dialog);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Dialog.WaitForResults(Future);
|
||||||
|
|
||||||
|
emit PackagesCooked();
|
||||||
|
return !Dialog.ShouldCancel();
|
||||||
|
}
|
||||||
|
else return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ SLOTS ************
|
// ************ SLOTS ************
|
||||||
|
|
|
@ -37,7 +37,10 @@ public:
|
||||||
bool OpenProject(const QString& rkProjPath);
|
bool OpenProject(const QString& rkProjPath);
|
||||||
void EditResource(CResourceEntry *pEntry);
|
void EditResource(CResourceEntry *pEntry);
|
||||||
void NotifyAssetsModified();
|
void NotifyAssetsModified();
|
||||||
void CookAllDirtyPackages();
|
|
||||||
|
bool CookPackage(CPackage *pPackage);
|
||||||
|
bool CookAllDirtyPackages();
|
||||||
|
bool CookPackageList(QList<CPackage*> PackageList);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CGameProject* ActiveProject() const { return mpActiveProject; }
|
inline CGameProject* ActiveProject() const { return mpActiveProject; }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "CExportGameDialog.h"
|
#include "CExportGameDialog.h"
|
||||||
#include "ui_CExportGameDialog.h"
|
#include "ui_CExportGameDialog.h"
|
||||||
|
#include "CProgressDialog.h"
|
||||||
#include "UICommon.h"
|
#include "UICommon.h"
|
||||||
|
|
||||||
#include <Common/AssertMacro.h>
|
#include <Common/AssertMacro.h>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
#include <nod/nod.hpp>
|
#include <nod/nod.hpp>
|
||||||
|
|
||||||
|
@ -383,10 +385,16 @@ void CExportGameDialog::Export()
|
||||||
CGameExporter Exporter(mGame, mRegion, mGameTitle, mGameID, mBuildVer);
|
CGameExporter Exporter(mGame, mRegion, mGameTitle, mGameID, mBuildVer);
|
||||||
TString StrExportDir = TO_TSTRING(ExportDir);
|
TString StrExportDir = TO_TSTRING(ExportDir);
|
||||||
StrExportDir.EnsureEndsWith('/');
|
StrExportDir.EnsureEndsWith('/');
|
||||||
mExportSuccess = Exporter.Export(mpDisc, StrExportDir, &NameMap, &GameInfo);
|
|
||||||
|
CProgressDialog Dialog("Creating new game project", true, parentWidget());
|
||||||
|
QFuture<bool> Future = QtConcurrent::run(&Exporter, &CGameExporter::Export, mpDisc, StrExportDir, &NameMap, &GameInfo, &Dialog);
|
||||||
|
mExportSuccess = Dialog.WaitForResults(Future);
|
||||||
|
|
||||||
if (!mExportSuccess)
|
if (!mExportSuccess)
|
||||||
UICommon::ErrorMsg(this, "Export failed!");
|
{
|
||||||
|
if (!Dialog.ShouldCancel())
|
||||||
|
UICommon::ErrorMsg(this, "Export failed!");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
mNewProjectPath = TO_QSTRING(Exporter.ProjectPath());
|
mNewProjectPath = TO_QSTRING(Exporter.ProjectPath());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,280 +0,0 @@
|
||||||
#ifndef CPAKTOOLDIALOG
|
|
||||||
#define CPAKTOOLDIALOG
|
|
||||||
|
|
||||||
#include <Common/EGame.h>
|
|
||||||
#include <Common/Log.h>
|
|
||||||
#include <Common/types.h>
|
|
||||||
#include "Editor/UICommon.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
class CPakToolDialog : public QProgressDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum EResult { eSuccess, eError, eUserCancelled };
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { eExtract, eRepack, eListDump } mMode;
|
|
||||||
QProcess *mpPakTool;
|
|
||||||
QString mPakFilename;
|
|
||||||
QString mListFilename;
|
|
||||||
QString mFolderPath;
|
|
||||||
EGame mGame;
|
|
||||||
EResult mResult;
|
|
||||||
|
|
||||||
QString mPartialString;
|
|
||||||
bool mUpdating;
|
|
||||||
|
|
||||||
int mCur;
|
|
||||||
int mMax;
|
|
||||||
bool mSetMax;
|
|
||||||
|
|
||||||
// Private Functions
|
|
||||||
CPakToolDialog(QWidget *pParent = 0)
|
|
||||||
: QProgressDialog(pParent)
|
|
||||||
, mpPakTool(nullptr)
|
|
||||||
, mSetMax(false)
|
|
||||||
, mUpdating(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual QSize sizeHint() const
|
|
||||||
{
|
|
||||||
QSize Size = QProgressDialog::sizeHint();
|
|
||||||
Size.rwidth() *= 3;
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
mpPakTool = new QProcess(this);
|
|
||||||
QStringList Args;
|
|
||||||
|
|
||||||
if (mMode == eExtract)
|
|
||||||
{
|
|
||||||
Args << "-x" << mPakFilename;
|
|
||||||
setLabelText("Extracting...");
|
|
||||||
}
|
|
||||||
else if (mMode == eRepack)
|
|
||||||
{
|
|
||||||
Args << "-r" << GameString(mGame) << mFolderPath << mPakFilename << mListFilename;
|
|
||||||
setLabelText("Repacking...");
|
|
||||||
}
|
|
||||||
else if (mMode == eListDump)
|
|
||||||
Args << "-d" << mPakFilename;
|
|
||||||
|
|
||||||
setWindowTitle(labelText());
|
|
||||||
|
|
||||||
// List dump is really fast, so showing progress dialog isn't necessary for it.
|
|
||||||
if (mMode != eListDump)
|
|
||||||
{
|
|
||||||
connect(mpPakTool, SIGNAL(readyReadStandardOutput()), this, SLOT(ReadStdOut()));
|
|
||||||
connect(mpPakTool, SIGNAL(finished(int)), this, SLOT(PakToolFinished(int)));
|
|
||||||
mpPakTool->start("PakTool.exe", Args);
|
|
||||||
exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mpPakTool->start("PakTool.exe", Args);
|
|
||||||
mpPakTool->waitForFinished(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult Result() const
|
|
||||||
{
|
|
||||||
if (wasCanceled()) return eUserCancelled;
|
|
||||||
else return (EResult) result();
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void ReadStdOut()
|
|
||||||
{
|
|
||||||
if (mUpdating) return;
|
|
||||||
mUpdating = true;
|
|
||||||
|
|
||||||
QString StdOut = mpPakTool->readAllStandardOutput();
|
|
||||||
QStringList Strings = StdOut.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts);
|
|
||||||
|
|
||||||
if (!Strings.isEmpty())
|
|
||||||
{
|
|
||||||
Strings.front().prepend(mPartialString);
|
|
||||||
|
|
||||||
QCharRef LastChar = StdOut[StdOut.size() - 1];
|
|
||||||
if (LastChar != '\n' && LastChar != '\r')
|
|
||||||
{
|
|
||||||
mPartialString = Strings.back();
|
|
||||||
|
|
||||||
if (Strings.size() > 1)
|
|
||||||
Strings.pop_back();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mPartialString = "";
|
|
||||||
|
|
||||||
const QRegExp kExtracting("^Extracting file ([0-9]{1,6}) of ([0-9]{1,6})");
|
|
||||||
const QRegExp kRepacking("^Repacking file ([0-9]{1,6}) of ([0-9]{1,6})");
|
|
||||||
const QRegExp& rkRegExp = (mMode == eExtract ? kExtracting : kRepacking);
|
|
||||||
|
|
||||||
int Result = rkRegExp.indexIn(Strings.last());
|
|
||||||
|
|
||||||
if (Result != -1)
|
|
||||||
{
|
|
||||||
mCur = rkRegExp.cap(1).toInt();
|
|
||||||
mMax = rkRegExp.cap(2).toInt();
|
|
||||||
|
|
||||||
if (!mSetMax)
|
|
||||||
{
|
|
||||||
setMinimum(0);
|
|
||||||
setMaximum(mMax);
|
|
||||||
mSetMax = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deferring UI updates is necessary because trying to do them on this thread causes crashes for a lot of people
|
|
||||||
QTimer::singleShot(0, this, SLOT(UpdateUI()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mUpdating = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateUI()
|
|
||||||
{
|
|
||||||
setLabelText(QString("%1 file %2 of %3...").arg(mMode == eExtract ? "Extracting" : "Repacking").arg(mCur).arg(mMax));
|
|
||||||
setWindowTitle(labelText());
|
|
||||||
setValue(mCur);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PakToolFinished(int ExitCode)
|
|
||||||
{
|
|
||||||
while (mUpdating) {}
|
|
||||||
done(ExitCode == 0 ? eSuccess : eError);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static EResult Extract(QString PakFilename, QString *pOutFolder = 0, QWidget *pParent = 0)
|
|
||||||
{
|
|
||||||
Log::Write("Extracting pak " + TO_TSTRING(PakFilename));
|
|
||||||
|
|
||||||
CPakToolDialog Dialog(pParent);
|
|
||||||
Dialog.mMode = eExtract;
|
|
||||||
Dialog.mPakFilename = PakFilename;
|
|
||||||
Dialog.Run();
|
|
||||||
EResult Result = Dialog.Result();
|
|
||||||
|
|
||||||
if (pOutFolder)
|
|
||||||
{
|
|
||||||
QFileInfo Pak(PakFilename);
|
|
||||||
*pOutFolder = Pak.absolutePath() + '/' + Pak.baseName() + "-pak/";
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::Write("Result: " + TO_TSTRING(ResultString(Result)));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EResult Repack(EGame Game, QString TargetPak, QString ListFile, QString FolderPath, QString *pOutPak = 0, QWidget *pParent = 0)
|
|
||||||
{
|
|
||||||
Log::Write("Repacking folder " + TO_TSTRING(FolderPath) + " into pak " + TO_TSTRING(TargetPak));
|
|
||||||
|
|
||||||
CPakToolDialog Dialog(pParent);
|
|
||||||
Dialog.mMode = eRepack;
|
|
||||||
Dialog.mPakFilename = TargetPak;
|
|
||||||
Dialog.mListFilename = ListFile;
|
|
||||||
Dialog.mFolderPath = FolderPath;
|
|
||||||
Dialog.mGame = Game;
|
|
||||||
Dialog.Run();
|
|
||||||
EResult Result = Dialog.Result();
|
|
||||||
|
|
||||||
if (pOutPak)
|
|
||||||
*pOutPak = TargetPak;
|
|
||||||
|
|
||||||
Log::Write("Result: " + TO_TSTRING(ResultString(Result)));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EResult DumpList(QString PakFilename, QString *pOutTxt = 0, QWidget *pParent = 0)
|
|
||||||
{
|
|
||||||
Log::Write("Dumping file list for pak " + TO_TSTRING(PakFilename));
|
|
||||||
|
|
||||||
CPakToolDialog Dialog(pParent);
|
|
||||||
Dialog.mMode = eListDump;
|
|
||||||
Dialog.mPakFilename = PakFilename;
|
|
||||||
Dialog.Run();
|
|
||||||
EResult Result = Dialog.Result();
|
|
||||||
|
|
||||||
if (pOutTxt)
|
|
||||||
{
|
|
||||||
QFileInfo Pak(PakFilename);
|
|
||||||
*pOutTxt = Pak.absolutePath() + '/' + Pak.baseName() + "-pak.txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::Write("Result: " + TO_TSTRING(ResultString(Result)));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString TargetPakForFolder(QString Folder)
|
|
||||||
{
|
|
||||||
QDir Dir(Folder);
|
|
||||||
QString PakName = Dir.dirName();
|
|
||||||
if (PakName.endsWith("-pak")) PakName.chop(4);
|
|
||||||
Dir.cdUp();
|
|
||||||
QString DirName = Dir.absolutePath();
|
|
||||||
|
|
||||||
QString PakPath = DirName + '/' + PakName + ".pak";
|
|
||||||
|
|
||||||
if (QFile::exists(PakPath))
|
|
||||||
return PakPath;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString TargetListForFolder(QString Folder)
|
|
||||||
{
|
|
||||||
QDir Dir(Folder);
|
|
||||||
QString TxtName = Dir.dirName();
|
|
||||||
Dir.cdUp();
|
|
||||||
QString DirName = Dir.absolutePath();
|
|
||||||
|
|
||||||
QString ListPath = DirName + '/' + TxtName + ".txt";
|
|
||||||
|
|
||||||
if (QFile::exists(ListPath))
|
|
||||||
return ListPath;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString GameString(EGame Game)
|
|
||||||
{
|
|
||||||
switch (Game)
|
|
||||||
{
|
|
||||||
case ePrimeDemo: return "mp1demo";
|
|
||||||
case ePrime: return "mp1";
|
|
||||||
case eEchoesDemo: return "mp2demo";
|
|
||||||
case eEchoes: return "mp2";
|
|
||||||
case eCorruptionProto: return "mp3proto";
|
|
||||||
case eCorruption: return "mp3";
|
|
||||||
case eReturns: return "dkcr";
|
|
||||||
default: return "INVALID";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString ResultString(EResult Result)
|
|
||||||
{
|
|
||||||
switch (Result)
|
|
||||||
{
|
|
||||||
case eSuccess: return "Success";
|
|
||||||
case eError: return "Error";
|
|
||||||
case eUserCancelled: return "User Cancelled";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPAKTOOLDIALOG
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include "CProgressDialog.h"
|
||||||
|
#include "ui_CProgressDialog.h"
|
||||||
|
#include "CEditorApplication.h"
|
||||||
|
#include <QCloseEvent>
|
||||||
|
|
||||||
|
CProgressDialog::CProgressDialog(QString OperationName, bool AlertOnFinish, QWidget *pParent)
|
||||||
|
: IProgressNotifierUI(pParent)
|
||||||
|
, mpUI(new Ui::CProgressDialog)
|
||||||
|
, mAlertOnFinish(AlertOnFinish)
|
||||||
|
, mFinished(false)
|
||||||
|
, mCanceled(false)
|
||||||
|
{
|
||||||
|
mpUI->setupUi(this);
|
||||||
|
mpUI->ProgressBar->setMinimum(0);
|
||||||
|
mpUI->ProgressBar->setMaximum(10000);
|
||||||
|
setWindowTitle(OperationName);
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
QWinTaskbarButton *pButton = new QWinTaskbarButton(this);
|
||||||
|
QWindow *pWindow = parentWidget()->windowHandle();
|
||||||
|
ASSERT(pWindow);
|
||||||
|
pButton->setWindow(pWindow);
|
||||||
|
|
||||||
|
mpTaskbarProgress = pButton->progress();
|
||||||
|
mpTaskbarProgress->setMinimum(0);
|
||||||
|
mpTaskbarProgress->setMaximum(10000);
|
||||||
|
mpTaskbarProgress->show();
|
||||||
|
|
||||||
|
setWindowFlags(windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
connect(mpUI->CancelButton, SIGNAL(pressed()), this, SLOT(CancelButtonClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
CProgressDialog::~CProgressDialog()
|
||||||
|
{
|
||||||
|
delete mpUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CProgressDialog::DisallowCanceling()
|
||||||
|
{
|
||||||
|
mpUI->CancelButton->setHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CProgressDialog::ShouldCancel() const
|
||||||
|
{
|
||||||
|
return mCanceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CProgressDialog::closeEvent(QCloseEvent *pEvent)
|
||||||
|
{
|
||||||
|
if (!mFinished)
|
||||||
|
{
|
||||||
|
CancelButtonClicked();
|
||||||
|
pEvent->ignore();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEvent->accept();
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
mpTaskbarProgress->reset();
|
||||||
|
mpTaskbarProgress->hide();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CProgressDialog::FinishAndClose()
|
||||||
|
{
|
||||||
|
mFinished = true;
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CProgressDialog::CancelButtonClicked()
|
||||||
|
{
|
||||||
|
mCanceled = true;
|
||||||
|
mpUI->CancelButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CProgressDialog::UpdateUI(const QString& rkTaskDesc, const QString& rkStepDesc, float ProgressPercent)
|
||||||
|
{
|
||||||
|
mpUI->TaskLabel->setText(rkTaskDesc);
|
||||||
|
mpUI->StepLabel->setText(rkStepDesc);
|
||||||
|
|
||||||
|
int ProgressValue = 10000 * ProgressPercent;
|
||||||
|
mpUI->ProgressBar->setValue(ProgressValue);
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
mpTaskbarProgress->setValue(ProgressValue);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
#ifndef CPROGRESSDIALOG_H
|
||||||
|
#define CPROGRESSDIALOG_H
|
||||||
|
|
||||||
|
#include "IProgressNotifierUI.h"
|
||||||
|
#include "UICommon.h"
|
||||||
|
#include <Core/GameProject/CGameProject.h>
|
||||||
|
#include <Core/IProgressNotifier.h>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
#include <QtWinExtras/QWinTaskbarButton>
|
||||||
|
#include <QtWinExtras/QWinTaskbarProgress>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CProgressDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CProgressDialog : public IProgressNotifierUI
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Ui::CProgressDialog *mpUI;
|
||||||
|
bool mAlertOnFinish;
|
||||||
|
bool mFinished;
|
||||||
|
bool mCanceled;
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
QWinTaskbarProgress *mpTaskbarProgress;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CProgressDialog(QString OperationName, bool AlertOnFinish, QWidget *pParent = 0);
|
||||||
|
~CProgressDialog();
|
||||||
|
|
||||||
|
void DisallowCanceling();
|
||||||
|
|
||||||
|
// IProgressNotifier interface
|
||||||
|
virtual bool ShouldCancel() const;
|
||||||
|
|
||||||
|
// Slots
|
||||||
|
public slots:
|
||||||
|
void closeEvent(QCloseEvent *pEvent);
|
||||||
|
void FinishAndClose();
|
||||||
|
void CancelButtonClicked();
|
||||||
|
void UpdateUI(const QString& rkTaskDesc, const QString& rkStepDesc, float ProgressPercent);
|
||||||
|
|
||||||
|
// Results
|
||||||
|
protected:
|
||||||
|
template<typename RetType>
|
||||||
|
void InternalWaitForResults(QFuture<RetType> Future)
|
||||||
|
{
|
||||||
|
gpEdApp->SetEditorTicksEnabled(false);
|
||||||
|
|
||||||
|
QFutureWatcher<RetType> Watcher;
|
||||||
|
connect(&Watcher, SIGNAL(finished()), this, SLOT(FinishAndClose()));
|
||||||
|
Watcher.setFuture(Future);
|
||||||
|
exec();
|
||||||
|
|
||||||
|
gpEdApp->SetEditorTicksEnabled(true);
|
||||||
|
|
||||||
|
if (mAlertOnFinish)
|
||||||
|
gpEdApp->alert(parentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename RetType>
|
||||||
|
RetType WaitForResults(QFuture<RetType> Future)
|
||||||
|
{
|
||||||
|
InternalWaitForResults(Future);
|
||||||
|
return Future.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void WaitForResults(QFuture<void> Future)
|
||||||
|
{
|
||||||
|
InternalWaitForResults(Future);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CPROGRESSDIALOG_H
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CProgressDialog</class>
|
||||||
|
<widget class="QDialog" name="CProgressDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>609</width>
|
||||||
|
<height>110</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="TaskLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="StepLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>8</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="ProgressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="CancelButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -2,12 +2,16 @@
|
||||||
#include "ui_CProjectSettingsDialog.h"
|
#include "ui_CProjectSettingsDialog.h"
|
||||||
#include "CEditorApplication.h"
|
#include "CEditorApplication.h"
|
||||||
#include "CExportGameDialog.h"
|
#include "CExportGameDialog.h"
|
||||||
|
#include "CProgressDialog.h"
|
||||||
#include "UICommon.h"
|
#include "UICommon.h"
|
||||||
#include "Editor/ResourceBrowser/CResourceBrowser.h"
|
#include "Editor/ResourceBrowser/CResourceBrowser.h"
|
||||||
#include <Common/AssertMacro.h>
|
#include <Common/AssertMacro.h>
|
||||||
#include <Core/GameProject/CGameExporter.h>
|
#include <Core/GameProject/CGameExporter.h>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
CProjectSettingsDialog::CProjectSettingsDialog(QWidget *pParent)
|
CProjectSettingsDialog::CProjectSettingsDialog(QWidget *pParent)
|
||||||
: QDialog(pParent)
|
: QDialog(pParent)
|
||||||
|
@ -22,6 +26,7 @@ CProjectSettingsDialog::CProjectSettingsDialog(QWidget *pParent)
|
||||||
|
|
||||||
connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(ActiveProjectChanged(CGameProject*)));
|
connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(ActiveProjectChanged(CGameProject*)));
|
||||||
connect(gpEdApp, SIGNAL(AssetsModified()), this, SLOT(SetupPackagesList()));
|
connect(gpEdApp, SIGNAL(AssetsModified()), this, SLOT(SetupPackagesList()));
|
||||||
|
connect(gpEdApp, SIGNAL(PackagesCooked()), this, SLOT(SetupPackagesList()));
|
||||||
|
|
||||||
// Set build ISO button color
|
// Set build ISO button color
|
||||||
QPalette Palette = mpUI->BuildIsoButton->palette();
|
QPalette Palette = mpUI->BuildIsoButton->palette();
|
||||||
|
@ -91,15 +96,13 @@ void CProjectSettingsDialog::CookPackage()
|
||||||
if (PackageIdx != -1)
|
if (PackageIdx != -1)
|
||||||
{
|
{
|
||||||
CPackage *pPackage = mpProject->PackageByIndex(PackageIdx);
|
CPackage *pPackage = mpProject->PackageByIndex(PackageIdx);
|
||||||
pPackage->Cook();
|
gpEdApp->CookPackage(pPackage);
|
||||||
SetupPackagesList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CProjectSettingsDialog::CookAllDirtyPackages()
|
void CProjectSettingsDialog::CookAllDirtyPackages()
|
||||||
{
|
{
|
||||||
gpEdApp->CookAllDirtyPackages();
|
gpEdApp->CookAllDirtyPackages();
|
||||||
SetupPackagesList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CProjectSettingsDialog::BuildISO()
|
void CProjectSettingsDialog::BuildISO()
|
||||||
|
@ -107,12 +110,17 @@ void CProjectSettingsDialog::BuildISO()
|
||||||
CGameProject *pProj = gpEdApp->ActiveProject();
|
CGameProject *pProj = gpEdApp->ActiveProject();
|
||||||
ASSERT(pProj && !pProj->IsWiiBuild());
|
ASSERT(pProj && !pProj->IsWiiBuild());
|
||||||
|
|
||||||
QString DefaultPath = TO_QSTRING(pProj->ProjectRoot() + pProj->Name()) + ".gcm";
|
QString DefaultPath = TO_QSTRING( pProj->ProjectRoot() + FileUtil::SanitizeName(pProj->Name(), false) + ".gcm" );
|
||||||
QString IsoPath = UICommon::SaveFileDialog(this, "Choose output ISO path", "*.gcm", DefaultPath);
|
QString IsoPath = UICommon::SaveFileDialog(this, "Choose output ISO path", "*.gcm", DefaultPath);
|
||||||
|
|
||||||
if (!IsoPath.isEmpty())
|
if (!IsoPath.isEmpty())
|
||||||
{
|
{
|
||||||
if (!pProj->BuildISO( TO_TSTRING(IsoPath) ))
|
if (gpEdApp->CookAllDirtyPackages())
|
||||||
UICommon::ErrorMsg(this, "Failed to build ISO! Check the log for details.");
|
{
|
||||||
|
CProgressDialog Dialog("Building ISO", true, this);
|
||||||
|
Dialog.DisallowCanceling();
|
||||||
|
QFuture<void> Future = QtConcurrent::run(pProj, &CGameProject::BuildISO, TO_TSTRING(IsoPath), &Dialog);
|
||||||
|
Dialog.WaitForResults(Future);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,10 @@ QMAKE_CXXFLAGS += /WX
|
||||||
DEFINES += PWE_EDITOR
|
DEFINES += PWE_EDITOR
|
||||||
RESOURCES += Icons.qrc
|
RESOURCES += Icons.qrc
|
||||||
|
|
||||||
win32: RC_ICONS += icons/AppIcon.ico
|
win32: {
|
||||||
|
RC_ICONS += icons/AppIcon.ico
|
||||||
|
QT += winextras
|
||||||
|
}
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
DESTDIR = $$PWD/../../bin
|
DESTDIR = $$PWD/../../bin
|
||||||
|
@ -156,8 +159,6 @@ HEADERS += \
|
||||||
Undo/CCloneSelectionCommand.h \
|
Undo/CCloneSelectionCommand.h \
|
||||||
CNodeCopyMimeData.h \
|
CNodeCopyMimeData.h \
|
||||||
Undo/CPasteNodesCommand.h \
|
Undo/CPasteNodesCommand.h \
|
||||||
CPakToolDialog.h \
|
|
||||||
WorldEditor/CRepackInfoDialog.h \
|
|
||||||
CAboutDialog.h \
|
CAboutDialog.h \
|
||||||
CharacterEditor/CCharacterEditor.h \
|
CharacterEditor/CCharacterEditor.h \
|
||||||
CharacterEditor/CCharacterEditorViewport.h \
|
CharacterEditor/CCharacterEditorViewport.h \
|
||||||
|
@ -179,7 +180,9 @@ HEADERS += \
|
||||||
Widgets/CTimedLineEdit.h \
|
Widgets/CTimedLineEdit.h \
|
||||||
CProjectSettingsDialog.h \
|
CProjectSettingsDialog.h \
|
||||||
WorldEditor/CPoiMapSidebar.h \
|
WorldEditor/CPoiMapSidebar.h \
|
||||||
WorldEditor/CWorldEditorSidebar.h
|
WorldEditor/CWorldEditorSidebar.h \
|
||||||
|
CProgressDialog.h \
|
||||||
|
IProgressNotifierUI.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -231,7 +234,6 @@ SOURCES += \
|
||||||
Undo/CCreateInstanceCommand.cpp \
|
Undo/CCreateInstanceCommand.cpp \
|
||||||
Undo/CCloneSelectionCommand.cpp \
|
Undo/CCloneSelectionCommand.cpp \
|
||||||
Undo/CPasteNodesCommand.cpp \
|
Undo/CPasteNodesCommand.cpp \
|
||||||
WorldEditor/CRepackInfoDialog.cpp \
|
|
||||||
CAboutDialog.cpp \
|
CAboutDialog.cpp \
|
||||||
CharacterEditor/CCharacterEditor.cpp \
|
CharacterEditor/CCharacterEditor.cpp \
|
||||||
CharacterEditor/CCharacterEditorViewport.cpp \
|
CharacterEditor/CCharacterEditorViewport.cpp \
|
||||||
|
@ -246,7 +248,8 @@ SOURCES += \
|
||||||
WorldEditor/CWorldTreeModel.cpp \
|
WorldEditor/CWorldTreeModel.cpp \
|
||||||
CProjectSettingsDialog.cpp \
|
CProjectSettingsDialog.cpp \
|
||||||
WorldEditor/CPoiMapSidebar.cpp \
|
WorldEditor/CPoiMapSidebar.cpp \
|
||||||
WorldEditor/CWorldEditorSidebar.cpp
|
WorldEditor/CWorldEditorSidebar.cpp \
|
||||||
|
CProgressDialog.cpp
|
||||||
|
|
||||||
# UI Files
|
# UI Files
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
@ -263,7 +266,6 @@ FORMS += \
|
||||||
WorldEditor/CTemplateEditDialog.ui \
|
WorldEditor/CTemplateEditDialog.ui \
|
||||||
WorldEditor/CLinkDialog.ui \
|
WorldEditor/CLinkDialog.ui \
|
||||||
WorldEditor/CSelectInstanceDialog.ui \
|
WorldEditor/CSelectInstanceDialog.ui \
|
||||||
WorldEditor/CRepackInfoDialog.ui \
|
|
||||||
CAboutDialog.ui \
|
CAboutDialog.ui \
|
||||||
CharacterEditor/CCharacterEditor.ui \
|
CharacterEditor/CCharacterEditor.ui \
|
||||||
WorldEditor/CCollisionRenderSettingsDialog.ui \
|
WorldEditor/CCollisionRenderSettingsDialog.ui \
|
||||||
|
@ -271,4 +273,5 @@ FORMS += \
|
||||||
CExportGameDialog.ui \
|
CExportGameDialog.ui \
|
||||||
WorldEditor/CWorldInfoSidebar.ui \
|
WorldEditor/CWorldInfoSidebar.ui \
|
||||||
CProjectSettingsDialog.ui \
|
CProjectSettingsDialog.ui \
|
||||||
WorldEditor/CPoiMapSidebar.ui
|
WorldEditor/CPoiMapSidebar.ui \
|
||||||
|
CProgressDialog.ui
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef IPROGRESSNOTIFIERUI_H
|
||||||
|
#define IPROGRESSNOTIFIERUI_H
|
||||||
|
|
||||||
|
#include "UICommon.h"
|
||||||
|
#include <Core/IProgressNotifier.h>
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
// IProgressNotifier subclass for UI classes (dialogs, etc)
|
||||||
|
class IProgressNotifierUI : public QDialog, public IProgressNotifier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IProgressNotifierUI(QWidget *pParent = 0)
|
||||||
|
: QDialog(pParent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void UpdateUI(const QString& rkTaskDesc, const QString& rkStepDesc, float ProgressPercent) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void UpdateProgress(const TString& rkTaskDesc, const TString& rkStepDesc, float ProgressPercent) final
|
||||||
|
{
|
||||||
|
// Defer the function call to make sure UI updates are done on the main thread
|
||||||
|
QMetaObject::invokeMethod(this, "UpdateUI", Qt::AutoConnection,
|
||||||
|
Q_ARG(QString, TO_QSTRING(rkTaskDesc)),
|
||||||
|
Q_ARG(QString, TO_QSTRING(rkStepDesc)),
|
||||||
|
Q_ARG(float, ProgressPercent) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IPROGRESSNOTIFIERUI_H
|
|
@ -1,114 +0,0 @@
|
||||||
#include "CRepackInfoDialog.h"
|
|
||||||
#include "ui_CRepackInfoDialog.h"
|
|
||||||
#include "Editor/CPakToolDialog.h"
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
CRepackInfoDialog::CRepackInfoDialog(QString TargetFolder, QString ListFile, QString OutputPak, QWidget *pParent /*= 0*/)
|
|
||||||
: QDialog(pParent)
|
|
||||||
, ui(new Ui::CRepackInfoDialog)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
ui->FolderLineEdit->setText(TargetFolder);
|
|
||||||
ui->FileListLineEdit->setText(ListFile);
|
|
||||||
ui->OutputPakLineEdit->setText(OutputPak);
|
|
||||||
UpdateStatus();
|
|
||||||
|
|
||||||
connect(ui->FolderToolButton, SIGNAL(clicked()), this, SLOT(BrowseFolderClicked()));
|
|
||||||
connect(ui->FileListToolButton, SIGNAL(clicked()), this, SLOT(BrowseListClicked()));
|
|
||||||
connect(ui->OutputPakToolButton, SIGNAL(clicked()), this, SLOT(BrowseOutPakClicked()));
|
|
||||||
connect(ui->FolderLineEdit, SIGNAL(textChanged(QString)), this, SLOT(UpdateStatus()));
|
|
||||||
connect(ui->FileListLineEdit, SIGNAL(textChanged(QString)), this, SLOT(UpdateStatus()));
|
|
||||||
connect(ui->OutputPakLineEdit, SIGNAL(textChanged(QString)), this, SLOT(UpdateStatus()));
|
|
||||||
}
|
|
||||||
|
|
||||||
CRepackInfoDialog::~CRepackInfoDialog()
|
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRepackInfoDialog::TargetFolderValid() const
|
|
||||||
{
|
|
||||||
return QDir(ui->FolderLineEdit->text()).exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRepackInfoDialog::ListFileValid() const
|
|
||||||
{
|
|
||||||
return QFile::exists(ui->FileListLineEdit->text());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRepackInfoDialog::OutputPakValid() const
|
|
||||||
{
|
|
||||||
return QFile::exists(ui->OutputPakLineEdit->text());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CRepackInfoDialog::TargetFolder() const
|
|
||||||
{
|
|
||||||
return ui->FolderLineEdit->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CRepackInfoDialog::ListFile() const
|
|
||||||
{
|
|
||||||
return ui->FileListLineEdit->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CRepackInfoDialog::OutputPak() const
|
|
||||||
{
|
|
||||||
return ui->OutputPakLineEdit->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ************ PUBLIC SLOTS ************
|
|
||||||
void CRepackInfoDialog::BrowseFolderClicked()
|
|
||||||
{
|
|
||||||
QString Folder = UICommon::OpenDirDialog(this, "Choose directory");
|
|
||||||
|
|
||||||
if (!Folder.isEmpty())
|
|
||||||
{
|
|
||||||
ui->FolderLineEdit->setText(Folder);
|
|
||||||
ui->FolderLineEdit->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CRepackInfoDialog::BrowseListClicked()
|
|
||||||
{
|
|
||||||
QString List = UICommon::OpenFileDialog(this, "Open list file", "All supported files (*.txt *.pak);;Text file (*.txt);;Pak file (*.pak)");
|
|
||||||
|
|
||||||
if (!List.isEmpty())
|
|
||||||
{
|
|
||||||
if (List.endsWith(".txt"))
|
|
||||||
ui->FileListLineEdit->setText(List);
|
|
||||||
|
|
||||||
else if (List.endsWith(".pak"))
|
|
||||||
{
|
|
||||||
QString Txt;
|
|
||||||
CPakToolDialog::DumpList(List, &Txt);
|
|
||||||
ui->FileListLineEdit->setText(Txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->FileListLineEdit->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CRepackInfoDialog::BrowseOutPakClicked()
|
|
||||||
{
|
|
||||||
QString Pak = UICommon::SaveFileDialog(this, "Save pak", "Pak File (*.pak)");
|
|
||||||
|
|
||||||
if (!Pak.isEmpty())
|
|
||||||
{
|
|
||||||
ui->OutputPakLineEdit->setText(Pak);
|
|
||||||
ui->OutputPakLineEdit->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CRepackInfoDialog::UpdateStatus()
|
|
||||||
{
|
|
||||||
static const QString skInvalidStylesheet = "border: 1px solid red";
|
|
||||||
|
|
||||||
ui->FolderLineEdit->setStyleSheet(TargetFolderValid() ? "" : skInvalidStylesheet);
|
|
||||||
ui->FileListLineEdit->setStyleSheet(ListFileValid() ? "" : skInvalidStylesheet);
|
|
||||||
ui->OutputPakLineEdit->setStyleSheet(OutputPakValid() ? "" : skInvalidStylesheet);
|
|
||||||
ui->ButtonBox->button(QDialogButtonBox::Ok)->setEnabled(TargetFolderValid() && ListFileValid() && OutputPakValid());
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef CREPACKINFODIALOG_H
|
|
||||||
#define CREPACKINFODIALOG_H
|
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class CRepackInfoDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CRepackInfoDialog : public QDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Ui::CRepackInfoDialog *ui;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit CRepackInfoDialog(QString TargetFolder, QString ListFile, QString OutputPak, QWidget *pParent = 0);
|
|
||||||
~CRepackInfoDialog();
|
|
||||||
|
|
||||||
bool TargetFolderValid() const;
|
|
||||||
bool ListFileValid() const;
|
|
||||||
bool OutputPakValid() const;
|
|
||||||
|
|
||||||
QString TargetFolder() const;
|
|
||||||
QString ListFile() const;
|
|
||||||
QString OutputPak() const;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void BrowseFolderClicked();
|
|
||||||
void BrowseListClicked();
|
|
||||||
void BrowseOutPakClicked();
|
|
||||||
void UpdateStatus();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CREPACKINFODIALOG_H
|
|
|
@ -1,127 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>CRepackInfoDialog</class>
|
|
||||||
<widget class="QDialog" name="CRepackInfoDialog">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>400</width>
|
|
||||||
<height>125</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Set Pak Info</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<layout class="QFormLayout" name="formLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="FolderLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Folder</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLineEdit" name="FolderLineEdit"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="FileListLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>File List</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="FileListLineEdit"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="OutputPakLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Output Pak</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLineEdit" name="OutputPakLineEdit"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="FolderToolButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="FileListToolButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="OutputPakToolButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="ButtonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>ButtonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>CRepackInfoDialog</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>248</x>
|
|
||||||
<y>254</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>157</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>ButtonBox</sender>
|
|
||||||
<signal>rejected()</signal>
|
|
||||||
<receiver>CRepackInfoDialog</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>316</x>
|
|
||||||
<y>260</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>286</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
|
@ -6,15 +6,15 @@
|
||||||
<property ID="0x01" name="Position" type="vector3f"/>
|
<property ID="0x01" name="Position" type="vector3f"/>
|
||||||
<property ID="0x02" name="Rotation" type="vector3f"/>
|
<property ID="0x02" name="Rotation" type="vector3f"/>
|
||||||
<property ID="0x03" name="Scale" type="vector3f"/>
|
<property ID="0x03" name="Scale" type="vector3f"/>
|
||||||
<property ID="0x04" name="Unknown 1" type="vector3f"/>
|
<property ID="0x04" name="Collision Extent" type="vector3f"/>
|
||||||
<property ID="0x05" name="Scan Offset" type="vector3f"/>
|
<property ID="0x05" name="Collision/Scan Offset" type="vector3f"/>
|
||||||
<property ID="0x06" name="Unknown 2" type="float"/>
|
<property ID="0x06" name="Mass" type="float"/>
|
||||||
<property ID="0x07" name="Unknown 3" type="float"/>
|
<property ID="0x07" name="Z Momentum" type="float"/>
|
||||||
<struct ID="0x08" name="HealthInfo" template="Structs/HealthInfo.xml"/>
|
<struct ID="0x08" name="HealthInfo" template="Structs/HealthInfo.xml"/>
|
||||||
<struct ID="0x09" name="DamageVulnerability" template="Structs/DamageVulnerability.xml"/>
|
<struct ID="0x09" name="DamageVulnerability" template="Structs/DamageVulnerability.xml"/>
|
||||||
<property ID="0x0A" name="AnimationParameters" type="character"/>
|
<property ID="0x0A" name="AnimationParameters" type="character"/>
|
||||||
<struct ID="0x0B" name="ActorParameters" template="Structs/ActorParameters.xml"/>
|
<struct ID="0x0B" name="ActorParameters" template="Structs/ActorParameters.xml"/>
|
||||||
<property ID="0x0C" name="Particle" type="asset" extensions="PART"/>
|
<property ID="0x0C" name="Flame Particle" type="asset" extensions="PART"/>
|
||||||
<struct ID="0x0D" name="DamageInfo" template="Structs/DamageInfo.xml"/>
|
<struct ID="0x0D" name="DamageInfo" template="Structs/DamageInfo.xml"/>
|
||||||
<property ID="0x0E" name="Active" type="bool"/>
|
<property ID="0x0E" name="Active" type="bool"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
Loading…
Reference in New Issue