You're breathtaking!
This commit is contained in:
86
Source/Editor/Cooker/Steps/CollectAssetsStep.cpp
Normal file
86
Source/Editor/Cooker/Steps/CollectAssetsStep.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "CollectAssetsStep.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Content/Assets/CubeTexture.h"
|
||||
#include "Engine/Content/Assets/Shader.h"
|
||||
#include "Engine/Content/Cache/AssetsCache.h"
|
||||
|
||||
bool CollectAssetsStep::Process(CookingData& data, Asset* asset)
|
||||
{
|
||||
// Skip virtual/temporary assets
|
||||
if (asset->IsVirtual())
|
||||
return false;
|
||||
|
||||
// Keep reference to the asset
|
||||
AssetReference<Asset> ref(asset);
|
||||
|
||||
// Asset should have loaded data
|
||||
if (asset->WaitForLoaded())
|
||||
return false;
|
||||
|
||||
// Gather asset references
|
||||
_references.Clear();
|
||||
asset->Locker.Lock();
|
||||
asset->GetReferences(_references);
|
||||
asset->Locker.Unlock();
|
||||
_assetsQueue.Add(_references);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollectAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
LOG(Info, "Searching for assets to include in a build. Using {0} root assets.", data.RootAssets.Count());
|
||||
data.StepProgress(TEXT("Collecting assets"), 0);
|
||||
|
||||
// Initialize assets queue
|
||||
_assetsQueue.Clear();
|
||||
_assetsQueue.EnsureCapacity(1024);
|
||||
for (auto i = data.RootAssets.Begin(); i.IsNotEnd(); ++i)
|
||||
_assetsQueue.Add(i->Item);
|
||||
|
||||
// Iterate through the assets graph
|
||||
AssetInfo assetInfo;
|
||||
while (_assetsQueue.HasItems())
|
||||
{
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
const auto assetId = _assetsQueue.Dequeue();
|
||||
|
||||
// Skip already processed or invalid assets
|
||||
if (!assetId.IsValid()
|
||||
|| !Content::GetRegistry()->FindAsset(assetId, assetInfo)
|
||||
|| data.Assets.Contains(assetId))
|
||||
continue;
|
||||
|
||||
// Skip some assets (with no refs and not required to load)
|
||||
if (assetInfo.TypeName == Texture::TypeName ||
|
||||
assetInfo.TypeName == CubeTexture::TypeName ||
|
||||
assetInfo.TypeName == Shader::TypeName)
|
||||
{
|
||||
LOG_STR(Info, assetInfo.Path);
|
||||
data.Assets.Add(assetId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load asset
|
||||
const auto asset = Content::LoadAsync<Asset>(assetId);
|
||||
if (asset == nullptr)
|
||||
continue;
|
||||
|
||||
// Process that asset
|
||||
LOG_STR(Info, asset->GetPath());
|
||||
data.Assets.Add(assetId);
|
||||
Process(data, asset);
|
||||
}
|
||||
|
||||
data.Stats.TotalAssets = data.Assets.Count();
|
||||
LOG(Info, "Found {0} assets to deploy!", data.Assets.Count());
|
||||
|
||||
return false;
|
||||
}
|
||||
26
Source/Editor/Cooker/Steps/CollectAssetsStep.h
Normal file
26
Source/Editor/Cooker/Steps/CollectAssetsStep.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
class Asset;
|
||||
|
||||
/// <summary>
|
||||
/// Cooking step that uses the root assets collection to find all dependant assets to include in the build.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class CollectAssetsStep : public GameCooker::BuildStep
|
||||
{
|
||||
private:
|
||||
|
||||
Array<Guid> _assetsQueue;
|
||||
Array<Guid> _references;
|
||||
|
||||
bool Process(CookingData& data, Asset* asset);
|
||||
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
298
Source/Editor/Cooker/Steps/CompileScriptsStep.cpp
Normal file
298
Source/Editor/Cooker/Steps/CompileScriptsStep.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "CompileScriptsStep.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Serialization/Json.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Editor/Editor.h"
|
||||
|
||||
bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, const String& projectFolderPath)
|
||||
{
|
||||
if (_deployedBuilds.Contains(path))
|
||||
return false;
|
||||
LOG(Info, "Deploying binaries from build {0}", path);
|
||||
_deployedBuilds.Add(path);
|
||||
|
||||
// Read file contents
|
||||
Array<byte> fileData;
|
||||
if (File::ReadAllBytes(path, fileData))
|
||||
{
|
||||
LOG(Error, "Failed to read file {0} contents.", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse Json data
|
||||
rapidjson_flax::Document document;
|
||||
document.Parse((const char*)fileData.Get(), fileData.Count());
|
||||
if (document.HasParseError())
|
||||
{
|
||||
LOG(Error, "Failed to parse {0} file contents.", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deploy all references
|
||||
auto referencesMember = document.FindMember("References");
|
||||
if (referencesMember != document.MemberEnd())
|
||||
{
|
||||
auto& referencesArray = referencesMember->value;
|
||||
ASSERT(referencesArray.IsArray());
|
||||
for (rapidjson::SizeType i = 0; i < referencesArray.Size(); i++)
|
||||
{
|
||||
auto& reference = referencesArray[i];
|
||||
String referenceProjectPath = JsonTools::GetString(reference, "ProjectPath", String::Empty);
|
||||
String referencePath = JsonTools::GetString(reference, "Path", String::Empty);
|
||||
if (referenceProjectPath.IsEmpty() || referencePath.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Empty reference in {0}.", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
Scripting::ProcessBuildInfoPath(referenceProjectPath, projectFolderPath);
|
||||
Scripting::ProcessBuildInfoPath(referencePath, projectFolderPath);
|
||||
|
||||
String referenceProjectFolderPath = StringUtils::GetDirectoryName(referenceProjectPath);
|
||||
|
||||
if (DeployBinaries(data, referencePath, referenceProjectFolderPath))
|
||||
{
|
||||
LOG(Error, "Failed to load reference in {0} to {1}.", path, referenceProjectPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy all binary modules
|
||||
auto binaryModulesMember = document.FindMember("BinaryModules");
|
||||
if (binaryModulesMember != document.MemberEnd())
|
||||
{
|
||||
auto& binaryModulesArray = binaryModulesMember->value;
|
||||
ASSERT(binaryModulesArray.IsArray());
|
||||
for (rapidjson::SizeType i = 0; i < binaryModulesArray.Size(); i++)
|
||||
{
|
||||
auto& binaryModule = binaryModulesArray[i];
|
||||
auto& e = data.BinaryModules.AddOne();
|
||||
const auto nameMember = binaryModule.FindMember("Name");
|
||||
if (nameMember == binaryModule.MemberEnd())
|
||||
{
|
||||
LOG(Error, "Failed to process file {0}. Missing binary module name.", path);
|
||||
return true;
|
||||
}
|
||||
e.Name = nameMember->value.GetText();
|
||||
StringAnsi nameAnsi(nameMember->value.GetString(), nameMember->value.GetStringLength());
|
||||
e.NativePath = JsonTools::GetString(binaryModule, "NativePath", String::Empty);
|
||||
e.ManagedPath = JsonTools::GetString(binaryModule, "ManagedPath", String::Empty);
|
||||
|
||||
Scripting::ProcessBuildInfoPath(e.NativePath, projectFolderPath);
|
||||
Scripting::ProcessBuildInfoPath(e.ManagedPath, projectFolderPath);
|
||||
|
||||
e.NativePath = StringUtils::GetFileName(e.NativePath);
|
||||
e.ManagedPath = StringUtils::GetFileName(e.ManagedPath);
|
||||
|
||||
LOG(Info, "Collecting binary module {0}", e.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy files
|
||||
Array<String> files(16);
|
||||
const String outputPath = StringUtils::GetDirectoryName(path);
|
||||
FileSystem::DirectoryGetFiles(files, outputPath, TEXT("*.*"), DirectorySearchOption::TopDirectoryOnly);
|
||||
for (int32 i = files.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
bool skip = false;
|
||||
const String& file = files[i];
|
||||
for (auto& extension : _extensionsToSkip)
|
||||
{
|
||||
if (file.EndsWith(extension))
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
files.RemoveAt(i);
|
||||
}
|
||||
for (auto& file : files)
|
||||
{
|
||||
const String dst = data.OutputPath / StringUtils::GetFileName(file);
|
||||
if (dst != file && FileSystem::CopyFile(dst, file))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy file from {0} to {1}."), file, dst);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompileScriptsStep::Perform(CookingData& data)
|
||||
{
|
||||
data.StepProgress(TEXT("Compiling game scripts"), 0);
|
||||
|
||||
const ProjectInfo* project = Editor::Project;
|
||||
const String& target = project->GameTarget;
|
||||
if (target.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Empty GameTarget in project.");
|
||||
return true;
|
||||
}
|
||||
const Char *platform, *architecture, *configuration = ::ToString(data.Configuration);
|
||||
switch (data.Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::Windows64:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::UWPx86:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::UWPx64:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxOne:
|
||||
platform = TEXT("XboxOne");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
platform = TEXT("Linux");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::PS4:
|
||||
platform = TEXT("PS4");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxScarlett:
|
||||
platform = TEXT("XboxScarlett");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::AndroidARM64:
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
_extensionsToSkip.Clear();
|
||||
_extensionsToSkip.Add(TEXT(".exp"));
|
||||
_extensionsToSkip.Add(TEXT(".ilk"));
|
||||
_extensionsToSkip.Add(TEXT(".lib"));
|
||||
_extensionsToSkip.Add(TEXT(".a"));
|
||||
_extensionsToSkip.Add(TEXT(".Build.json"));
|
||||
if (data.Configuration == BuildConfiguration::Release)
|
||||
{
|
||||
_extensionsToSkip.Add(TEXT(".xml"));
|
||||
_extensionsToSkip.Add(TEXT(".pdb"));
|
||||
}
|
||||
_deployedBuilds.Clear();
|
||||
data.BinaryModules.Clear();
|
||||
|
||||
if (data.Tools->OnScriptsCompilationStart(data))
|
||||
return true;
|
||||
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
// Compile the scripts
|
||||
LOG(Info, "Starting scripts compilation for game...");
|
||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||
auto args = String::Format(
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3}"),
|
||||
target, platform, architecture, configuration, logFile);
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
{
|
||||
// Skip building C++ for Linux on Windows (no need to install cross-toolchain to build C# game)
|
||||
args += TEXT(" -BuildBindingsOnly");
|
||||
|
||||
// Assume FlaxGame was prebuilt for Linux
|
||||
args += TEXT(" -SkipTargets=FlaxGame");
|
||||
}
|
||||
#endif
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to compile game scripts."));
|
||||
return true;
|
||||
}
|
||||
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnScriptsCompilationEnd(data))
|
||||
return true;
|
||||
|
||||
data.StepProgress(TEXT("Exporting binaries"), 0.8f);
|
||||
|
||||
// Deploy binary modules
|
||||
const String targetBuildInfo = project->ProjectFolderPath / TEXT("Binaries") / project->GameTarget / platform / architecture / configuration / target + TEXT(".Build.json");
|
||||
if (DeployBinaries(data, targetBuildInfo, project->ProjectFolderPath))
|
||||
return true;
|
||||
|
||||
data.StepProgress(TEXT("Generating merged build info"), 0.95f);
|
||||
|
||||
// Generate merged build info for all deployed binary modules
|
||||
{
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
#if BUILD_DEBUG
|
||||
PrettyJsonWriter writerObj(buffer);
|
||||
#else
|
||||
CompactJsonWriter writerObj(buffer);
|
||||
#endif
|
||||
JsonWriter& writer = writerObj;
|
||||
|
||||
writer.StartObject();
|
||||
{
|
||||
writer.JKEY("Name");
|
||||
writer.String(target);
|
||||
writer.JKEY("Platform");
|
||||
writer.String(platform);
|
||||
writer.JKEY("Configuration");
|
||||
writer.String(configuration);
|
||||
|
||||
writer.JKEY("BinaryModules");
|
||||
writer.StartArray();
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
{
|
||||
writer.StartObject();
|
||||
|
||||
writer.JKEY("Name");
|
||||
writer.String(binaryModule.Name);
|
||||
|
||||
if (binaryModule.NativePath.HasChars())
|
||||
{
|
||||
writer.JKEY("NativePath");
|
||||
writer.String(binaryModule.NativePath);
|
||||
}
|
||||
|
||||
if (binaryModule.ManagedPath.HasChars())
|
||||
{
|
||||
writer.JKEY("ManagedPath");
|
||||
writer.String(binaryModule.ManagedPath);
|
||||
}
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
writer.EndObject();
|
||||
|
||||
const String outputBuildInfo = data.OutputPath / TEXT("Game.Build.json");
|
||||
if (File::WriteAllBytes(outputBuildInfo, (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||
{
|
||||
LOG(Error, "Failed to save binary modules info file {0}.", outputBuildInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Tools->OnScriptsStepDone(data))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
24
Source/Editor/Cooker/Steps/CompileScriptsStep.h
Normal file
24
Source/Editor/Cooker/Steps/CompileScriptsStep.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Game scripts compilation step. Outputs proper assemblies compiled to the target platform.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class CompileScriptsStep : public GameCooker::BuildStep
|
||||
{
|
||||
private:
|
||||
|
||||
Array<String, FixedAllocation<8>> _extensionsToSkip;
|
||||
Array<String, InlinedAllocation<32>> _deployedBuilds;
|
||||
|
||||
bool DeployBinaries(CookingData& data, const String& path, const String& projectFolderPath);
|
||||
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
1144
Source/Editor/Cooker/Steps/CookAssetsStep.cpp
Normal file
1144
Source/Editor/Cooker/Steps/CookAssetsStep.cpp
Normal file
File diff suppressed because it is too large
Load Diff
187
Source/Editor/Cooker/Steps/CookAssetsStep.h
Normal file
187
Source/Editor/Cooker/Steps/CookAssetsStep.h
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "Engine/Core/Types/Pair.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Content/AssetInfo.h"
|
||||
#include "Engine/Content/Cache/AssetsCache.h"
|
||||
|
||||
class Asset;
|
||||
class BinaryAsset;
|
||||
class JsonAssetBase;
|
||||
struct AssetInitData;
|
||||
|
||||
/// <summary>
|
||||
/// Cooking step that builds all the assets and packages them to the output directory.
|
||||
/// Uses incremental build cache to provide faster building.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class FLAXENGINE_API CookAssetsStep : public GameCooker::BuildStep
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Array<Pair<String, DateTime>> FileDependenciesList;
|
||||
|
||||
/// <summary>
|
||||
/// Cached cooked asset entry data.
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API CacheEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The asset identifier.
|
||||
/// </summary>
|
||||
Guid ID;
|
||||
|
||||
/// <summary>
|
||||
/// The stored data full typename. Used to recognize asset type.
|
||||
/// </summary>
|
||||
String TypeName;
|
||||
|
||||
/// <summary>
|
||||
/// The asset file modification time.
|
||||
/// </summary>
|
||||
DateTime FileModified;
|
||||
|
||||
/// <summary>
|
||||
/// The list of files on which this entry depends on. Cached date is the last edit time used to discard cache result on modification.
|
||||
/// </summary>
|
||||
FileDependenciesList FileDependencies;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Assets cooking cache data (incremental building feature).
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API CacheData
|
||||
{
|
||||
/// <summary>
|
||||
/// The cache header file path.
|
||||
/// </summary>
|
||||
String HeaderFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// The cached files folder.
|
||||
/// </summary>
|
||||
String CacheFolder;
|
||||
|
||||
/// <summary>
|
||||
/// The build options used to cook assets. Changing some options in game settings might trigger cached assets invalidation.
|
||||
/// </summary>
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool SupportDX11;
|
||||
bool SupportDX10;
|
||||
bool SupportVulkan;
|
||||
} Windows;
|
||||
|
||||
struct
|
||||
{
|
||||
bool SupportDX11;
|
||||
bool SupportDX10;
|
||||
} UWP;
|
||||
|
||||
struct
|
||||
{
|
||||
bool SupportVulkan;
|
||||
} Linux;
|
||||
|
||||
struct
|
||||
{
|
||||
bool ShadersNoOptimize;
|
||||
bool ShadersGenerateDebugData;
|
||||
} Global;
|
||||
} Settings;
|
||||
|
||||
/// <summary>
|
||||
/// The cached entries.
|
||||
/// </summary>
|
||||
Dictionary<Guid, CacheEntry> Entries;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the asset of the given id (file may be missing).
|
||||
/// </summary>
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <param name="cachedFilePath">The cached file path to use for creating cache storage.</param>
|
||||
void GetFilePath(const Guid& id, String& cachedFilePath) const
|
||||
{
|
||||
cachedFilePath = CacheFolder / id.ToString(Guid::FormatType::N);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new entry for the cooked asset file.
|
||||
/// </summary>
|
||||
/// <param name="asset">The asset.</param>
|
||||
/// <param name="cachedFilePath">The cached file path to use for creating cache storage.</param>
|
||||
/// <returns>The added entry reference.</returns>
|
||||
CacheEntry& CreateEntry(const JsonAssetBase* asset, String& cachedFilePath);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new entry for the cooked asset file.
|
||||
/// </summary>
|
||||
/// <param name="asset">The asset.</param>
|
||||
/// <param name="cachedFilePath">The cached file path to use for creating cache storage.</param>
|
||||
/// <returns>The added entry reference.</returns>
|
||||
CacheEntry& CreateEntry(const Asset* asset, String& cachedFilePath);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all cached entries for assets that contain a shader. This forces rebuild for them.
|
||||
/// </summary>
|
||||
void InvalidateShaders();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the cache for the given cooking data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
void Load(CookingData& data);
|
||||
|
||||
/// <summary>
|
||||
/// Saves this cache (header file).
|
||||
/// </summary>
|
||||
void Save();
|
||||
};
|
||||
|
||||
struct FLAXENGINE_API AssetCookData
|
||||
{
|
||||
CookingData& Data;
|
||||
CacheData& Cache;
|
||||
AssetInitData& InitData;
|
||||
Asset* Asset;
|
||||
FileDependenciesList& FileDependencies;
|
||||
};
|
||||
|
||||
typedef bool (*ProcessAssetFunc)(AssetCookData&);
|
||||
|
||||
/// <summary>
|
||||
/// The asset processors (key: asset full typename, value: processor function that cooks the asset).
|
||||
/// </summary>
|
||||
static Dictionary<String, ProcessAssetFunc> AssetProcessors;
|
||||
|
||||
static bool ProcessDefaultAsset(AssetCookData& options);
|
||||
|
||||
private:
|
||||
|
||||
AssetsCache::Registry AssetsRegistry;
|
||||
AssetsCache::PathsMapping AssetPathsMapping;
|
||||
|
||||
bool Process(CookingData& data, CacheData& cache, Asset* asset);
|
||||
bool Process(CookingData& data, CacheData& cache, BinaryAsset* asset);
|
||||
bool Process(CookingData& data, CacheData& cache, JsonAssetBase* asset);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CookAssetsStep"/> class.
|
||||
/// </summary>
|
||||
CookAssetsStep();
|
||||
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
120
Source/Editor/Cooker/Steps/DeployDataStep.cpp
Normal file
120
Source/Editor/Cooker/Steps/DeployDataStep.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DeployDataStep.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Renderer/ReflectionsPass.h"
|
||||
#include "Engine/Renderer/AntiAliasing/SMAA.h"
|
||||
|
||||
bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
data.StepProgress(TEXT("Deploying engine data"), 0);
|
||||
const String depsRoot = data.GetPlatformBinariesRoot();
|
||||
|
||||
// Setup output folders and copy required data
|
||||
const auto contentDir = data.OutputPath / TEXT("Content");
|
||||
if (FileSystem::DirectoryExists(contentDir))
|
||||
{
|
||||
// Remove old content files
|
||||
FileSystem::DeleteDirectory(contentDir, true);
|
||||
|
||||
// Give some time for Explorer (if location was viewed)
|
||||
Platform::Sleep(10);
|
||||
}
|
||||
FileSystem::CreateDirectory(contentDir);
|
||||
const auto srcMono = depsRoot / TEXT("Mono");
|
||||
const auto dstMono = data.OutputPath / TEXT("Mono");
|
||||
if (!FileSystem::DirectoryExists(dstMono))
|
||||
{
|
||||
if (!FileSystem::DirectoryExists(srcMono))
|
||||
{
|
||||
data.Error(TEXT("Missing Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FileSystem::CopyDirectory(dstMono, srcMono, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy engine data for the target platform
|
||||
if (data.Tools->OnDeployBinaries(data))
|
||||
return true;
|
||||
|
||||
// Register engine in-build assets
|
||||
data.AddRootEngineAsset(TEXT("Shaders/AtmospherePreCompute"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/ColorGrading"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/DebugDraw"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/DepthOfField"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/EyeAdaptation"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Fog"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Forward"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/FXAA"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/TAA"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/SMAA"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/GBuffer"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/GUI"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Histogram"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Lights"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/MultiScaler"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/PostProcessing"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/MotionBlur"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/BitonicSort"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/GPUParticlesSorting"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Quad"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Reflections"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Shadows"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/Sky"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/SSAO"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/SSR"));
|
||||
data.AddRootEngineAsset(TEXT("Shaders/VolumetricFog"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultMaterial"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultTerrainMaterial"));
|
||||
if (!GameSettings::NoSplashScreen && !GameSettings::SplashScreen.IsValid())
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Logo"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/WhiteTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensStarburst"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensColor"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensDirt"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Circle"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Hexagon"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Octagon"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Cross"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Models/Sphere"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Models/SphereLowPoly"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Models/Box"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Models/SimpleBox"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Models/Quad"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/SkyboxMaterial"));
|
||||
data.AddRootEngineAsset(PRE_INTEGRATED_GF_ASSET_NAME);
|
||||
data.AddRootEngineAsset(SMAA_AREA_TEX);
|
||||
data.AddRootEngineAsset(SMAA_SEARCH_TEX);
|
||||
|
||||
// Register game assets
|
||||
data.StepProgress(TEXT("Deploying game data"), 50);
|
||||
auto& buildSettings = *BuildSettings::Instance();
|
||||
for (auto& e : buildSettings.AdditionalAssets)
|
||||
data.AddRootAsset(e.GetID());
|
||||
Array<String> files;
|
||||
for (auto& e : buildSettings.AdditionalAssetFolders)
|
||||
{
|
||||
String path = FileSystem::ConvertRelativePathToAbsolute(Globals::ProjectFolder, e);
|
||||
if (FileSystem::DirectoryGetFiles(files, path, TEXT("*"), DirectorySearchOption::AllDirectories))
|
||||
{
|
||||
data.Error(TEXT("Failed to find additional assets to deploy."));
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto& q : files)
|
||||
data.AddRootAsset(q);
|
||||
files.Clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
17
Source/Editor/Cooker/Steps/DeployDataStep.h
Normal file
17
Source/Editor/Cooker/Steps/DeployDataStep.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Engine and game content and data files deployment step.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class DeployDataStep : public GameCooker::BuildStep
|
||||
{
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
9
Source/Editor/Cooker/Steps/PostProcessStep.cpp
Normal file
9
Source/Editor/Cooker/Steps/PostProcessStep.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "PostProcessStep.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
|
||||
bool PostProcessStep::Perform(CookingData& data)
|
||||
{
|
||||
return data.Tools->OnPostProcess(data);
|
||||
}
|
||||
17
Source/Editor/Cooker/Steps/PostProcessStep.h
Normal file
17
Source/Editor/Cooker/Steps/PostProcessStep.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Final cooking step that can perform custom set of actions on generated game data.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class PostProcessStep : public GameCooker::BuildStep
|
||||
{
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
78
Source/Editor/Cooker/Steps/PrecompileAssembliesStep.cpp
Normal file
78
Source/Editor/Cooker/Steps/PrecompileAssembliesStep.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "PrecompileAssembliesStep.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
|
||||
bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
{
|
||||
// Skip for some platforms
|
||||
if (!data.Tools->UseAOT())
|
||||
return false;
|
||||
LOG(Info, "Using AOT...");
|
||||
|
||||
// Useful references about AOT:
|
||||
// http://www.mono-project.com/docs/advanced/runtime/docs/aot/
|
||||
// http://www.mono-project.com/docs/advanced/aot/
|
||||
|
||||
const String infoMsg = TEXT("Running AOT");
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Setup
|
||||
PlatformTools::AotConfig config(data);
|
||||
data.Tools->OnConfigureAOT(data, config);
|
||||
|
||||
// Prepare output directory
|
||||
config.AotCachePath = data.OutputPath / TEXT("Mono/lib/mono/aot-cache");
|
||||
switch (data.Tools->GetArchitecture())
|
||||
{
|
||||
case ArchitectureType::x86:
|
||||
config.AotCachePath /= TEXT("x86");
|
||||
break;
|
||||
case ArchitectureType::x64:
|
||||
config.AotCachePath /= TEXT("amd64");
|
||||
break;
|
||||
default:
|
||||
data.Error(TEXT("Not supported AOT architecture"));
|
||||
return true;
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(config.AotCachePath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(config.AotCachePath))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup AOT output directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect assemblies for AOT
|
||||
// TODO: don't perform AOT on all assemblies but only ones used by the game and engine assemblies
|
||||
for (auto& dir : config.AssembliesSearchDirs)
|
||||
FileSystem::DirectoryGetFiles(config.Assemblies, dir, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
if (binaryModule.ManagedPath.HasChars())
|
||||
config.Assemblies.Add(data.OutputPath / binaryModule.ManagedPath);
|
||||
// TODO: move AOT to Flax.Build and perform it on all C# assemblies used in target build
|
||||
config.Assemblies.Add(data.OutputPath / TEXT("Newtonsoft.Json.dll"));
|
||||
|
||||
// Perform AOT for the assemblies
|
||||
for (int32 i = 0; i < config.Assemblies.Count(); i++)
|
||||
{
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPerformAOT(data, config, config.Assemblies[i]))
|
||||
return true;
|
||||
|
||||
data.StepProgress(infoMsg, static_cast<float>(i) / config.Assemblies.Count());
|
||||
}
|
||||
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPostProcessAOT(data, config))
|
||||
return true;
|
||||
|
||||
// TODO: maybe remove GAC/assemblies? aot-cache could be only used in the build game
|
||||
|
||||
return false;
|
||||
}
|
||||
18
Source/Editor/Cooker/Steps/PrecompileAssembliesStep.h
Normal file
18
Source/Editor/Cooker/Steps/PrecompileAssembliesStep.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Optional step used only on selected platform that precompiles C# script assemblies.
|
||||
/// Uses Mono Ahead of Time Compilation (AOT) feature.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class PrecompileAssembliesStep : public GameCooker::BuildStep
|
||||
{
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
73
Source/Editor/Cooker/Steps/ValidateStep.cpp
Normal file
73
Source/Editor/Cooker/Steps/ValidateStep.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ValidateStep.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
|
||||
bool ValidateStep::Perform(CookingData& data)
|
||||
{
|
||||
data.StepProgress(TEXT("Performing validation"), 0);
|
||||
|
||||
// Ensure output and cache directories exist
|
||||
if (!FileSystem::DirectoryExists(data.OutputPath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(data.OutputPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to create build output directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(data.CacheDirectory))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(data.CacheDirectory))
|
||||
{
|
||||
data.Error(TEXT("Failed to create build cache directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if OFFICIAL_BUILD
|
||||
// Validate that platform data is installed
|
||||
if (!FileSystem::DirectoryExists(data.GetGameBinariesPath()))
|
||||
{
|
||||
data.Error(TEXT("Missing platform data tools for the target platform. Use Flax Launcher and download the required package."));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load game settings (may be modified via editor)
|
||||
GameSettings::Load();
|
||||
data.AddRootAsset(Globals::ProjectContentFolder / TEXT("GameSettings.json"));
|
||||
|
||||
// Validate game settings
|
||||
{
|
||||
if (GameSettings::ProductName.IsEmpty())
|
||||
{
|
||||
data.Error(TEXT("Missing product name."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GameSettings::CompanyName.IsEmpty())
|
||||
{
|
||||
data.Error(TEXT("Missing company name."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: validate version
|
||||
|
||||
AssetInfo info;
|
||||
if (!Content::GetAssetInfo(GameSettings::FirstScene, info))
|
||||
{
|
||||
data.Error(TEXT("Missing first scene."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate more game config
|
||||
|
||||
// TODO: validate all input scenes?
|
||||
|
||||
return false;
|
||||
}
|
||||
17
Source/Editor/Cooker/Steps/ValidateStep.h
Normal file
17
Source/Editor/Cooker/Steps/ValidateStep.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Project data validation step. Ensures that game cooking can be started.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class ValidateStep : public GameCooker::BuildStep
|
||||
{
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
Reference in New Issue
Block a user