#include "MetaCorePlatform/MetaCoreWindow.h" #include "MetaCoreFoundation/MetaCoreGeneratedReflection.h" #include "MetaCoreRender/MetaCoreEditorViewportRenderer.h" #include "MetaCoreRender/MetaCoreRenderDevice.h" #include "MetaCoreRender/MetaCoreRenderTypes.h" #include "MetaCoreRuntimeData/MetaCoreRuntimeDataDispatcher.h" #include "MetaCoreRuntimeData/MetaCoreRuntimeDataProject.h" #include "MetaCoreRuntimeData/MetaCoreRuntimeDataSource.h" #include "MetaCoreScene/MetaCoreScenePackage.h" #include "MetaCoreScene/MetaCoreScene.h" #include #include #include namespace { MetaCore::MetaCoreSceneView MetaCoreBuildPlayerSceneView() { MetaCore::MetaCoreSceneView sceneView; sceneView.CameraPosition = {0.0F, 2.5F, 6.5F}; sceneView.CameraTarget = {0.0F, 0.7F, 0.0F}; sceneView.CameraUp = {0.0F, 1.0F, 0.0F}; sceneView.VerticalFieldOfViewDegrees = 60.0F; return sceneView; } [[nodiscard]] std::filesystem::path MetaCoreResolveRuntimePath(const std::filesystem::path& relativePath) { const std::vector candidates{ std::filesystem::current_path() / relativePath, std::filesystem::current_path() / ".." / ".." / ".." / relativePath, std::filesystem::current_path() / ".." / ".." / ".." / "TestProject" / "Runtime" / relativePath.filename() }; for (const std::filesystem::path& candidate : candidates) { std::error_code errorCode; if (std::filesystem::exists(candidate, errorCode)) { return std::filesystem::weakly_canonical(candidate, errorCode); } } return candidates.front(); } [[nodiscard]] std::filesystem::path MetaCoreResolveProjectPath(const std::filesystem::path& relativePath) { const std::vector candidates{ std::filesystem::current_path() / relativePath, std::filesystem::current_path() / ".." / ".." / ".." / relativePath }; for (const std::filesystem::path& candidate : candidates) { std::error_code errorCode; if (std::filesystem::exists(candidate, errorCode)) { return std::filesystem::weakly_canonical(candidate, errorCode); } } return candidates.front(); } [[nodiscard]] MetaCore::MetaCoreRuntimeProjectDocument MetaCoreBuildDefaultRuntimeProjectDocument() { MetaCore::MetaCoreRuntimeProjectDocument document; document.StartupScenePath = std::filesystem::path("Scenes") / "Main.mcscene"; document.DataSourcesPath = std::filesystem::path("Runtime") / "DataSources.mcruntime"; document.BindingsPath = std::filesystem::path("Runtime") / "Bindings.mcruntime"; document.DiagnosticsPath = std::filesystem::path("Runtime") / "Diagnostics.mcruntimestate"; return document; } [[nodiscard]] MetaCore::MetaCoreRuntimeDataSourcesDocument MetaCoreBuildDefaultRuntimeDataSourcesDocument() { MetaCore::MetaCoreRuntimeDataSourcesDocument document; document.Sources.push_back(MetaCore::MetaCoreDataSourceDefinition{ "replay-source", "file_replay", "Replay Source", {MetaCore::MetaCoreDataSourceSetting{"file_path", "TestProject/Runtime/RuntimeReplay.mcstream"}}, true, 1000 }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "cube.position", "replay-source", "cube.position", MetaCore::MetaCoreRuntimeValueType::Vec3 }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "cube.visible", "replay-source", "cube.visible", MetaCore::MetaCoreRuntimeValueType::Bool }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "cube.base_color", "replay-source", "cube.base_color", MetaCore::MetaCoreRuntimeValueType::Vec3 }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "valve.visible", "replay-source", "valve.visible", MetaCore::MetaCoreRuntimeValueType::Bool }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "tank.base_color", "replay-source", "tank.base_color", MetaCore::MetaCoreRuntimeValueType::Vec3 }); document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{ "alarm.intensity", "replay-source", "alarm.intensity", MetaCore::MetaCoreRuntimeValueType::Double }); return document; } [[nodiscard]] MetaCore::MetaCoreRuntimeBindingsDocument MetaCoreBuildDefaultRuntimeBindingsDocument() { MetaCore::MetaCoreRuntimeBindingsDocument document; document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.cube.position", "cube.position", 3, MetaCore::MetaCoreRuntimeBindingTarget::TransformPosition, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.cube.visible", "cube.visible", 3, MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererVisible, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.cube.base_color", "cube.base_color", 3, MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererBaseColor, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.valve.visible", "valve.visible", 4, MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererVisible, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.tank.base_color", "tank.base_color", 5, MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererBaseColor, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{ "binding.alarm.intensity", "alarm.intensity", 6, MetaCore::MetaCoreRuntimeBindingTarget::LightIntensity, MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue }); return document; } } // namespace int main(int argc, char* argv[]) { if (argc > 0) { std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path()); } MetaCore::MetaCoreWindow window; if (!window.Initialize(1280, 720, "MetaCore Player")) { std::cerr << "MetaCorePlayer: window initialize failed\n"; return 1; } MetaCore::MetaCoreRenderDevice renderDevice; if (!renderDevice.Initialize(window)) { std::cerr << "MetaCorePlayer: render device initialize failed\n"; return 1; } MetaCore::MetaCoreEditorViewportRenderer viewportRenderer; if (!viewportRenderer.Initialize(renderDevice)) { std::cerr << "MetaCorePlayer: viewport renderer initialize failed\n"; return 1; } const auto projectPath = MetaCoreResolveProjectPath("TestProject/MetaCore.project.json"); const std::filesystem::path projectRoot = projectPath.parent_path(); MetaCore::MetaCoreTypeRegistry typeRegistry; MetaCore::MetaCoreRegisterRuntimeDataGeneratedTypes(typeRegistry); const auto loadedRuntimeProjectDocument = MetaCore::MetaCoreReadRuntimeProjectDocument( projectRoot / "Runtime" / "ProjectRuntime.mcruntimecfg", typeRegistry ); const auto runtimeProjectDocument = loadedRuntimeProjectDocument.value_or(MetaCoreBuildDefaultRuntimeProjectDocument()); std::optional startupSceneDocument; if (!runtimeProjectDocument.StartupScenePath.empty()) { startupSceneDocument = MetaCore::MetaCoreReadScenePackage(projectRoot / runtimeProjectDocument.StartupScenePath); } if (!startupSceneDocument.has_value()) { startupSceneDocument = MetaCore::MetaCoreLoadStartupSceneDocument(projectPath); } MetaCore::MetaCoreScene scene; if (startupSceneDocument.has_value()) { MetaCore::MetaCoreSceneSnapshot snapshot; snapshot.GameObjects = startupSceneDocument->GameObjects; scene.RestoreSnapshot(snapshot); std::cout << "MetaCorePlayer: loaded startup scene from project " << projectPath.string() << '\n'; } else { scene = MetaCore::MetaCoreCreateDefaultScene(); std::cout << "MetaCorePlayer: startup scene unavailable, using built-in default scene\n"; } MetaCore::MetaCoreRuntimeDataDispatcher runtimeDataDispatcher(scene); const auto sourcesPath = MetaCoreResolveRuntimePath(projectRoot / runtimeProjectDocument.DataSourcesPath); const auto bindingsPath = MetaCoreResolveRuntimePath(projectRoot / runtimeProjectDocument.BindingsPath); const auto diagnosticsPath = MetaCoreResolveRuntimePath(projectRoot / runtimeProjectDocument.DiagnosticsPath); const auto loadedSourcesDocument = MetaCore::MetaCoreReadRuntimeDataSourcesDocument(sourcesPath, typeRegistry); const auto loadedBindingsDocument = MetaCore::MetaCoreReadRuntimeBindingsDocument(bindingsPath, typeRegistry); const auto sourcesDocument = loadedSourcesDocument.value_or(MetaCoreBuildDefaultRuntimeDataSourcesDocument()); const auto bindingsDocument = loadedBindingsDocument.value_or(MetaCoreBuildDefaultRuntimeBindingsDocument()); if (loadedSourcesDocument.has_value() && loadedBindingsDocument.has_value()) { std::cout << "MetaCorePlayer: loaded runtime config from binary .mcruntime documents\n"; } else { const bool sourcesExists = std::filesystem::exists(sourcesPath); const bool bindingsExists = std::filesystem::exists(bindingsPath); if ((sourcesExists && !loadedSourcesDocument.has_value()) || (bindingsExists && !loadedBindingsDocument.has_value())) { std::cerr << "MetaCorePlayer: runtime config exists but is unreadable or corrupted, using built-in fallback config\n"; } else { std::cout << "MetaCorePlayer: runtime config missing, using built-in fallback config\n"; } } runtimeDataDispatcher.SetDataPointDefinitions(sourcesDocument.DataPoints); runtimeDataDispatcher.SetBindingDefinitions(bindingsDocument.Bindings); std::unique_ptr runtimeAdapter; if (!sourcesDocument.Sources.empty()) { runtimeAdapter = MetaCore::MetaCoreCreateRuntimeDataSourceAdapter(sourcesDocument.Sources.front().AdapterType); if (runtimeAdapter == nullptr) { std::cerr << "MetaCorePlayer: unsupported adapter type " << sourcesDocument.Sources.front().AdapterType << '\n'; return 1; } if (!runtimeAdapter->Configure(sourcesDocument.Sources.front())) { std::cerr << "MetaCorePlayer: failed to configure runtime adapter error=" << runtimeAdapter->GetStatus().LastError << '\n'; return 1; } if (!runtimeAdapter->Connect()) { std::cerr << "MetaCorePlayer: failed to connect runtime adapter error=" << runtimeAdapter->GetStatus().LastError << '\n'; return 1; } } MetaCore::MetaCoreRuntimeDataSourceState lastReportedSourceState = runtimeAdapter != nullptr ? runtimeAdapter->GetStatus().State : MetaCore::MetaCoreRuntimeDataSourceState::Disconnected; std::uint64_t diagnosticsWriteFrame = 0; while (!window.ShouldClose()) { window.BeginFrame(); const auto [windowWidth, windowHeight] = window.GetWindowSize(); viewportRenderer.SetViewportRect(MetaCore::MetaCoreViewportRect{ 0.0F, 0.0F, static_cast(windowWidth), static_cast(windowHeight) }); if (runtimeAdapter != nullptr) { runtimeAdapter->Tick(1.0 / 60.0); runtimeDataDispatcher.ApplyUpdates(runtimeAdapter->PollUpdates()); runtimeDataDispatcher.TickStaleness(runtimeAdapter->GetStatus().LastUpdateAt); } const auto diagnostics = runtimeDataDispatcher.BuildDiagnosticsSnapshot( runtimeAdapter != nullptr ? std::vector{runtimeAdapter->GetStatus()} : std::vector{} ); if ((diagnosticsWriteFrame % 15ULL) == 0ULL) { (void)MetaCore::MetaCoreWriteRuntimeDiagnosticsSnapshot(diagnosticsPath, diagnostics, typeRegistry); } ++diagnosticsWriteFrame; if (runtimeAdapter != nullptr && runtimeAdapter->GetStatus().State != lastReportedSourceState) { std::cout << "MetaCorePlayer: data source state changed to " << static_cast(runtimeAdapter->GetStatus().State) << " error=" << runtimeAdapter->GetStatus().LastError << '\n'; lastReportedSourceState = runtimeAdapter->GetStatus().State; } if (diagnostics.HasFaults) { for (const MetaCore::MetaCoreRuntimeBindingStatus& bindingStatus : diagnostics.BindingStatuses) { if (!bindingStatus.Healthy || bindingStatus.Stale) { std::cout << "MetaCorePlayer: binding issue id=" << bindingStatus.BindingId << " stale=" << (bindingStatus.Stale ? "true" : "false") << " error=" << bindingStatus.LastError << '\n'; } } } viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView()); renderDevice.RenderFrame(); renderDevice.PresentFrame(); window.EndFrame(); } viewportRenderer.Shutdown(); renderDevice.Shutdown(); window.Shutdown(); return 0; }