diff --git a/Source/Editor/Cooker/CookingData.h b/Source/Editor/Cooker/CookingData.h
index 779b472a0..ef12d204e 100644
--- a/Source/Editor/Cooker/CookingData.h
+++ b/Source/Editor/Cooker/CookingData.h
@@ -285,24 +285,22 @@ public:
///
/// The total assets amount in the build.
///
- int32 TotalAssets;
+ int32 TotalAssets = 0;
///
/// The cooked assets (TotalAssets - CookedAssets is amount of reused cached assets).
///
- int32 CookedAssets;
+ int32 CookedAssets = 0;
///
- /// The final output content size in MB.
+ /// The final output content size (in bytes).
///
- int32 ContentSizeMB;
+ uint64 ContentSize = 0;
///
/// The asset type stats. Key is the asset typename, value is the stats container.
///
Dictionary AssetStats;
-
- Statistics();
};
///
@@ -328,6 +326,11 @@ public:
///
HashSet Assets;
+ ///
+ /// The final files collection to include in build (valid only after CollectAssetsStep).
+ ///
+ HashSet Files;
+
struct BinaryModuleInfo
{
String Name;
diff --git a/Source/Editor/Cooker/GameCooker.cpp b/Source/Editor/Cooker/GameCooker.cpp
index ba6dd012c..118dd397f 100644
--- a/Source/Editor/Cooker/GameCooker.cpp
+++ b/Source/Editor/Cooker/GameCooker.cpp
@@ -202,13 +202,6 @@ bool CookingData::AssetTypeStatistics::operator<(const AssetTypeStatistics& othe
return Count > other.Count;
}
-CookingData::Statistics::Statistics()
-{
- TotalAssets = 0;
- CookedAssets = 0;
- ContentSizeMB = 0;
-}
-
CookingData::CookingData(const SpawnParams& params)
: ScriptingObject(params)
{
diff --git a/Source/Editor/Cooker/Steps/CollectAssetsStep.cpp b/Source/Editor/Cooker/Steps/CollectAssetsStep.cpp
index 4787339e6..55e8b5037 100644
--- a/Source/Editor/Cooker/Steps/CollectAssetsStep.cpp
+++ b/Source/Editor/Cooker/Steps/CollectAssetsStep.cpp
@@ -29,7 +29,7 @@ bool CollectAssetsStep::Perform(CookingData& data)
while (assetsQueue.HasItems())
{
BUILD_STEP_CANCEL_CHECK;
- const auto assetId = assetsQueue.Dequeue();
+ const Guid assetId = assetsQueue.Dequeue();
// Skip already processed or invalid assets
if (!assetId.IsValid()
@@ -68,6 +68,11 @@ bool CollectAssetsStep::Perform(CookingData& data)
asset->GetReferences(references, files);
asset->Locker.Unlock();
assetsQueue.Add(references);
+ for (String& file : files)
+ {
+ if (file.HasChars())
+ data.Files.Add(MoveTemp(file));
+ }
}
data.Stats.TotalAssets = data.Assets.Count();
diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
index 2558181aa..52050708e 100644
--- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
+++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
@@ -891,7 +891,6 @@ bool CookAssetsStep::Process(CookingData& data, CacheData& cache, JsonAssetBase*
class PackageBuilder : public NonCopyable
{
private:
-
int32 _packageIndex;
int32 MaxAssetsPerPackage;
int32 MaxPackageSize;
@@ -904,7 +903,6 @@ private:
uint64 packagesSizeTotal;
public:
-
///
/// Initializes a new instance of the class.
///
@@ -933,7 +931,6 @@ public:
}
public:
-
uint64 GetPackagesSizeTotal() const
{
return packagesSizeTotal;
@@ -1042,8 +1039,11 @@ bool CookAssetsStep::Perform(CookingData& data)
float Step1ProgressEnd = 0.6f;
String Step1Info = TEXT("Cooking assets");
float Step2ProgressStart = Step1ProgressEnd;
- float Step2ProgressEnd = 0.9f;
- String Step2Info = TEXT("Packaging assets");
+ float Step2ProgressEnd = 0.8f;
+ String Step2Info = TEXT("Cooking files");
+ float Step3ProgressStart = Step2ProgressStart;
+ float Step3ProgressEnd = 0.9f;
+ String Step3Info = TEXT("Packaging assets");
data.StepProgress(TEXT("Loading build cache"), 0);
@@ -1100,11 +1100,14 @@ bool CookAssetsStep::Perform(CookingData& data)
#endif
int32 subStepIndex = 0;
AssetReference assetRef;
- assetRef.Unload.Bind([]() { LOG(Error, "Asset gets unloaded while cooking it!"); Platform::Sleep(100); });
+ assetRef.Unload.Bind([]
+ {
+ LOG(Error, "Asset got unloaded while cooking it!");
+ Platform::Sleep(100);
+ });
for (auto i = data.Assets.Begin(); i.IsNotEnd(); ++i)
{
BUILD_STEP_CANCEL_CHECK;
-
data.StepProgress(Step1Info, Math::Lerp(Step1ProgressStart, Step1ProgressEnd, static_cast(subStepIndex++) / data.Assets.Count()));
const Guid assetId = i->Item;
@@ -1184,6 +1187,35 @@ bool CookAssetsStep::Perform(CookingData& data)
// Save build cache header
cache.Save(data);
+ // Process all files
+ for (auto i = data.Files.Begin(); i.IsNotEnd(); ++i)
+ {
+ BUILD_STEP_CANCEL_CHECK;
+ data.StepProgress(Step2Info, Math::Lerp(Step2ProgressStart, Step2ProgressEnd, (float)subStepIndex++ / data.Files.Count()));
+ const String& filePath = i->Item;
+
+ // Calculate destination path
+ String cookedPath = data.DataOutputPath;
+ if (FileSystem::IsRelative(filePath))
+ cookedPath /= filePath;
+ else
+ cookedPath /= String(TEXT("Content")) / StringUtils::GetFileName(filePath);
+
+ // Copy file
+ if (!FileSystem::FileExists(cookedPath) || FileSystem::GetFileLastEditTime(cookedPath) >= FileSystem::GetFileLastEditTime(filePath))
+ {
+ if (FileSystem::CreateDirectory(StringUtils::GetDirectoryName(cookedPath)))
+ return true;
+ if (FileSystem::CopyFile(cookedPath, filePath))
+ return true;
+ }
+
+ // Count stats of file extension
+ auto& assetStats = data.Stats.AssetStats[FileSystem::GetExtension(cookedPath)];
+ assetStats.Count++;
+ assetStats.ContentSize += FileSystem::GetFileSize(cookedPath);
+ }
+
// Create build game header
{
GameHeaderFlags gameFlags = GameHeaderFlags::None;
@@ -1229,13 +1261,11 @@ bool CookAssetsStep::Perform(CookingData& data)
for (auto i = AssetsRegistry.Begin(); i.IsNotEnd(); ++i)
{
BUILD_STEP_CANCEL_CHECK;
-
- data.StepProgress(Step2Info, Math::Lerp(Step2ProgressStart, Step2ProgressEnd, static_cast(subStepIndex++) / AssetsRegistry.Count()));
+ data.StepProgress(Step3Info, Math::Lerp(Step3ProgressStart, Step3ProgressEnd, (float)subStepIndex++ / AssetsRegistry.Count()));
const auto assetId = i->Key;
String cookedFilePath;
cache.GetFilePath(assetId, cookedFilePath);
-
if (!FileSystem::FileExists(cookedFilePath))
{
LOG(Warning, "Missing cooked file for asset \'{0}\'", assetId);
@@ -1253,12 +1283,12 @@ bool CookAssetsStep::Perform(CookingData& data)
return true;
for (auto& e : data.Stats.AssetStats)
e.Value.TypeName = e.Key;
- data.Stats.ContentSizeMB = static_cast(packageBuilder.GetPackagesSizeTotal() / (1024 * 1024));
+ data.Stats.ContentSize += packageBuilder.GetPackagesSizeTotal();
}
BUILD_STEP_CANCEL_CHECK;
- data.StepProgress(TEXT("Creating assets cache"), Step2ProgressEnd);
+ data.StepProgress(TEXT("Creating assets cache"), Step3ProgressEnd);
// Create asset paths mapping for the assets.
// Assets mapping is use to convert paths used in Content::Load(path) into the asset id.
@@ -1291,7 +1321,7 @@ bool CookAssetsStep::Perform(CookingData& data)
}
// Print stats
- LOG(Info, "Cooked {0} assets, total assets: {1}, total content packages size: {2} MB", data.Stats.CookedAssets, AssetsRegistry.Count(), data.Stats.ContentSizeMB);
+ LOG(Info, "Cooked {0} assets, total assets: {1}, total content packages size: {2} MB", data.Stats.CookedAssets, AssetsRegistry.Count(), (int32)(data.Stats.ContentSize / (1024 * 1024)));
{
Array assetTypes;
data.Stats.AssetStats.GetValues(assetTypes);
diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp
index e9960d424..a06e53350 100644
--- a/Source/Engine/Content/JsonAsset.cpp
+++ b/Source/Engine/Content/JsonAsset.cpp
@@ -125,14 +125,26 @@ void FindIds(ISerializable::DeserializeStream& node, Array& output, Array<
FindIds(node[i], output, files);
}
}
- else if (node.IsString())
+ else if (node.IsString() && node.GetStringLength() != 0)
{
if (node.GetStringLength() == 32)
{
// Try parse as Guid in format `N` (32 hex chars)
Guid id;
if (!Guid::Parse(node.GetStringAnsiView(), id))
+ {
output.Add(id);
+ return;
+ }
+ }
+ if (node.GetStringLength() < 512)
+ {
+ // Try to detect file paths
+ String path = node.GetText();
+ if (FileSystem::FileExists(path))
+ {
+ files.Add(MoveTemp(path));
+ }
}
}
}