MetaCore/tools/MetaCoreBuildPackageTool/main.cpp

230 lines
8.3 KiB
C++

#include "MetaCoreEditor/MetaCoreBuiltinModules.h"
#include "MetaCoreEditor/MetaCoreEditorServices.h"
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
namespace {
void MetaCorePrintUsage() {
std::cerr
<< "Usage: MetaCoreBuildPackageTool <project-root> [options]\n"
<< "Options:\n"
<< " --player <path> Path to MetaCorePlayer.exe\n"
<< " --output <directory> Build output base directory\n"
<< " --platform <windows|linux|android|web>\n"
<< " --graphics <opengl|vulkan|webgl|webgpu>\n"
<< " --arch <x64|arm64|wasm32>\n"
<< " --no-cook Package without cooking first\n"
<< " --no-loose-content Do not copy loose Assets/Scenes\n"
<< " --no-runtime-config Do not copy Runtime configuration\n"
<< " --use-cooked-assets Enable cooked asset loading in packaged runtime config\n";
}
[[nodiscard]] bool MetaCoreParseBuildPlatform(
std::string_view value,
MetaCore::MetaCoreBuildPlatform& outputPlatform
) {
if (value == "windows") {
outputPlatform = MetaCore::MetaCoreBuildPlatform::Windows;
} else if (value == "linux") {
outputPlatform = MetaCore::MetaCoreBuildPlatform::Linux;
} else if (value == "android") {
outputPlatform = MetaCore::MetaCoreBuildPlatform::Android;
} else if (value == "web") {
outputPlatform = MetaCore::MetaCoreBuildPlatform::Web;
} else {
return false;
}
return true;
}
[[nodiscard]] bool MetaCoreParseGraphicsBackend(
std::string_view value,
MetaCore::MetaCoreGraphicsBackend& outputBackend
) {
if (value == "opengl") {
outputBackend = MetaCore::MetaCoreGraphicsBackend::OpenGL;
} else if (value == "vulkan") {
outputBackend = MetaCore::MetaCoreGraphicsBackend::Vulkan;
} else if (value == "webgl") {
outputBackend = MetaCore::MetaCoreGraphicsBackend::WebGL;
} else if (value == "webgpu") {
outputBackend = MetaCore::MetaCoreGraphicsBackend::WebGPU;
} else {
return false;
}
return true;
}
[[nodiscard]] bool MetaCoreParseBuildArchitecture(
std::string_view value,
MetaCore::MetaCoreBuildArchitecture& outputArchitecture
) {
if (value == "x64") {
outputArchitecture = MetaCore::MetaCoreBuildArchitecture::X64;
} else if (value == "arm64") {
outputArchitecture = MetaCore::MetaCoreBuildArchitecture::Arm64;
} else if (value == "wasm32") {
outputArchitecture = MetaCore::MetaCoreBuildArchitecture::Wasm32;
} else {
return false;
}
return true;
}
[[nodiscard]] bool MetaCoreSetProjectPathEnvironment(const std::filesystem::path& projectRoot) {
#if defined(_WIN32)
return _putenv_s("METACORE_PROJECT_PATH", projectRoot.string().c_str()) == 0;
#else
return setenv("METACORE_PROJECT_PATH", projectRoot.string().c_str(), 1) == 0;
#endif
}
[[nodiscard]] bool MetaCoreConsumePathOption(
int& index,
int argc,
char* argv[],
std::filesystem::path& outputPath
) {
if (index + 1 >= argc) {
return false;
}
++index;
outputPath = argv[index];
return true;
}
void MetaCorePrintDependencyReport(
const MetaCore::MetaCoreBuildPlayerPackageResult& result,
std::ostream& output
) {
output << "Dependencies: " << result.DependencyReport.size() << '\n';
for (const MetaCore::MetaCoreBuildDependencyReportEntry& entry : result.DependencyReport) {
if (entry.Status == "Cooked" || entry.Status == "SkippedGeneratedSubAsset") {
continue;
}
output << " [" << entry.Status << "] " << entry.AssetGuid.ToString()
<< " reason=" << entry.Reason;
if (entry.ReferencedBy.IsValid()) {
output << " referenced_by=" << entry.ReferencedBy.ToString();
}
if (!entry.AssetType.empty()) {
output << " type=" << entry.AssetType;
}
if (!entry.AssetPath.empty()) {
output << " path=" << entry.AssetPath.generic_string();
}
if (!entry.Message.empty()) {
output << " message=" << entry.Message;
}
output << '\n';
}
}
} // namespace
int main(int argc, char* argv[]) {
if (argc < 2) {
MetaCorePrintUsage();
return 1;
}
if (std::string_view(argv[1]) == "--help" || std::string_view(argv[1]) == "-h") {
MetaCorePrintUsage();
return 0;
}
const std::filesystem::path projectRoot = std::filesystem::absolute(argv[1]).lexically_normal();
if (!std::filesystem::exists(projectRoot / "MetaCore.project.json")) {
std::cerr << "MetaCore project descriptor was not found: "
<< (projectRoot / "MetaCore.project.json").string() << '\n';
return 1;
}
MetaCore::MetaCoreBuildPlayerPackageRequest request;
for (int index = 2; index < argc; ++index) {
const std::string_view argument = argv[index];
if (argument == "--player") {
if (!MetaCoreConsumePathOption(index, argc, argv, request.PlayerExecutablePath)) {
std::cerr << "--player requires a path\n";
return 1;
}
} else if (argument == "--output") {
if (!MetaCoreConsumePathOption(index, argc, argv, request.OutputDirectory)) {
std::cerr << "--output requires a directory\n";
return 1;
}
} else if (argument == "--platform") {
if (index + 1 >= argc || !MetaCoreParseBuildPlatform(argv[++index], request.Target.Platform)) {
std::cerr << "--platform requires one of: windows, linux, android, web\n";
return 1;
}
} else if (argument == "--graphics") {
if (index + 1 >= argc || !MetaCoreParseGraphicsBackend(argv[++index], request.Target.GraphicsBackend)) {
std::cerr << "--graphics requires one of: opengl, vulkan, webgl, webgpu\n";
return 1;
}
} else if (argument == "--arch") {
if (index + 1 >= argc || !MetaCoreParseBuildArchitecture(argv[++index], request.Target.Architecture)) {
std::cerr << "--arch requires one of: x64, arm64, wasm32\n";
return 1;
}
} else if (argument == "--no-cook") {
request.CookBeforePackage = false;
} else if (argument == "--no-loose-content") {
request.CopyLooseProjectContent = false;
} else if (argument == "--no-runtime-config") {
request.CopyRuntimeConfig = false;
} else if (argument == "--use-cooked-assets") {
request.UseCookedAssetsInPackage = true;
} else if (argument == "--help" || argument == "-h") {
MetaCorePrintUsage();
return 0;
} else {
std::cerr << "Unknown option: " << argument << '\n';
MetaCorePrintUsage();
return 1;
}
}
if (!MetaCoreSetProjectPathEnvironment(projectRoot)) {
std::cerr << "Failed to set METACORE_PROJECT_PATH\n";
return 1;
}
MetaCore::MetaCoreEditorModuleRegistry moduleRegistry;
const std::unique_ptr<MetaCore::MetaCoreIModule> coreServicesModule =
MetaCore::MetaCoreCreateBuiltinCoreServicesModule();
coreServicesModule->Startup(moduleRegistry);
const auto buildService = moduleRegistry.ResolveService<MetaCore::MetaCoreIBuildService>();
if (buildService == nullptr) {
coreServicesModule->Shutdown(moduleRegistry);
moduleRegistry.ShutdownServices();
std::cerr << "BuildService is not available\n";
return 1;
}
const MetaCore::MetaCoreBuildPlayerPackageResult result =
buildService->BuildPlayerPackage(request);
coreServicesModule->Shutdown(moduleRegistry);
moduleRegistry.ShutdownServices();
if (!result.Success) {
std::cerr << "Build package failed: " << result.Error << '\n';
MetaCorePrintDependencyReport(result, std::cerr);
return 1;
}
std::cout << "Build package created: " << result.OutputRoot.string() << '\n'
<< "Copied files: " << result.CopiedFiles.size() << '\n'
<< "Cooked assets: " << result.CookedAssets.size() << '\n';
MetaCorePrintDependencyReport(result, std::cout);
return 0;
}