#include "MetaCoreEditor/MetaCoreBuiltinModules.h" #include "MetaCoreEditor/MetaCoreEditorServices.h" #include #include #include #include #include #include namespace { void MetaCorePrintUsage() { std::cerr << "Usage: MetaCoreBuildPackageTool [options]\n" << "Options:\n" << " --player Path to MetaCorePlayer.exe\n" << " --output Build output base directory\n" << " --platform \n" << " --graphics \n" << " --arch \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 coreServicesModule = MetaCore::MetaCoreCreateBuiltinCoreServicesModule(); coreServicesModule->Startup(moduleRegistry); const auto buildService = moduleRegistry.ResolveService(); 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; }