From 781241742dc650353bd354868bd497d1f65011a9 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Sat, 18 Jul 2026 11:43:33 +0400 Subject: feat(runtime): trace visual graph phases --- crates/fparkan-assets/src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ crates/fparkan-runtime/src/lib.rs | 29 ++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/fparkan-assets/src/lib.rs b/crates/fparkan-assets/src/lib.rs index ba40ca8..aeb91d9 100644 --- a/crates/fparkan-assets/src/lib.rs +++ b/crates/fparkan-assets/src/lib.rs @@ -468,6 +468,17 @@ pub enum AssetPreparationPhase { Textures, } +/// Visual dependency class currently being expanded into a prototype graph. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum VisualDependencyPhase { + /// Resolve a mesh's WEAR table. + Wear, + /// Resolve MAT0 material documents selected by WEAR. + Material, + /// Validate diffuse TEXM textures and lightmaps. + Texture, +} + /// Errors raised while preparing CPU-side assets. #[derive(Debug)] pub enum AssetError { @@ -1103,6 +1114,29 @@ pub fn extend_graph_report_with_visual_dependencies( report: &mut PrototypeGraphReport, graph: &mut PrototypeGraph, prototypes: &[EffectivePrototype], +) { + extend_graph_report_with_visual_dependencies_and_progress( + repository, + report, + graph, + prototypes, + |_| {}, + ); +} + +/// Extends a prototype dependency report while reporting each visual dependency class. +/// +/// # Panics +/// +/// Panics only if the hard-coded, host-compatible `material.lib` path stops +/// satisfying the path policy, which indicates a programming error in this module. +#[allow(clippy::too_many_lines)] +pub fn extend_graph_report_with_visual_dependencies_and_progress( + repository: &R, + report: &mut PrototypeGraphReport, + graph: &mut PrototypeGraph, + prototypes: &[EffectivePrototype], + mut on_phase: impl FnMut(VisualDependencyPhase), ) { if graph.visual_dependencies_expanded { return; @@ -1140,6 +1174,7 @@ pub fn extend_graph_report_with_visual_dependencies( let mesh_parent_edge = mesh_edge_id(graph, prototype_node_id); let root_index = root_index_for_prototype(graph, prototype_index); + on_phase(VisualDependencyPhase::Wear); match resolve_wear_table(repository, mesh) { Ok(table) => { report.wear_resolved_count += 1; @@ -1178,6 +1213,7 @@ pub fn extend_graph_report_with_visual_dependencies( &mut next_edge, ); report.material_slot_count += table.entries.len(); + on_phase(VisualDependencyPhase::Material); for (material_index, _entry) in table.entries.iter().enumerate() { let Ok(material_index) = u16::try_from(material_index) else { push_visual_failure( @@ -1224,6 +1260,7 @@ pub fn extend_graph_report_with_visual_dependencies( &mut next_edge, ); for texture in material.document.texture_requests() { + on_phase(VisualDependencyPhase::Texture); report.texture_request_count += 1; match resolve_texm_validation_cached( repository, @@ -1284,6 +1321,7 @@ pub fn extend_graph_report_with_visual_dependencies( } } for lightmap in &table.lightmaps { + on_phase(VisualDependencyPhase::Texture); report.lightmap_request_count += 1; match resolve_texm_validation_cached( repository, diff --git a/crates/fparkan-runtime/src/lib.rs b/crates/fparkan-runtime/src/lib.rs index 9a35d65..ff7beda 100644 --- a/crates/fparkan-runtime/src/lib.rs +++ b/crates/fparkan-runtime/src/lib.rs @@ -22,10 +22,11 @@ use fparkan_assets::{ decode_mission_land_path, decode_mission_payload, decode_nres_payload, - derive_mission_land_paths, extend_graph_report_with_visual_dependencies, prepare_terrain_world, - AssetError as AssetPreparationError, AssetId, AssetManager, AssetPreparationPhase, - BuildCategory, MissionAssetPlan, MissionDocument, MissionError, MissionTerrainPaths, NresError, - PreparedVisual, TerrainFormatError, TerrainPreparationError, TerrainWorld, TmaProfile, + derive_mission_land_paths, extend_graph_report_with_visual_dependencies_and_progress, + prepare_terrain_world, AssetError as AssetPreparationError, AssetId, AssetManager, + AssetPreparationPhase, BuildCategory, MissionAssetPlan, MissionDocument, MissionError, + MissionTerrainPaths, NresError, PreparedVisual, TerrainFormatError, TerrainPreparationError, + TerrainWorld, TmaProfile, VisualDependencyPhase, }; use fparkan_path::{normalize_relative, NormalizedPath, PathError, PathPolicy}; use fparkan_prototype::{ @@ -118,6 +119,12 @@ pub enum MissionLoadPhase { Graph, /// Expand model-backed visual dependencies of the prototype graph. GraphVisuals, + /// Resolve WEAR tables while expanding visual dependencies. + GraphVisualWears, + /// Resolve MAT0 documents while expanding visual dependencies. + GraphVisualMaterials, + /// Validate TEXM documents while expanding visual dependencies. + GraphVisualTextures, /// Prepare all reachable visual/resource dependencies. Assets, /// Decode and validate MSH model meshes. @@ -693,11 +700,23 @@ fn load_mission_with_options_and_progress( let (mut prototype_graph, resolved_prototypes, mut prototype_report) = build_prototype_graph_report(&repository, vfs.as_ref(), scoped_graph_roots); record_load_phase(&mut trace, &mut on_phase, MissionLoadPhase::GraphVisuals); - extend_graph_report_with_visual_dependencies( + let mut last_graph_visual_phase = None; + extend_graph_report_with_visual_dependencies_and_progress( &repository, &mut prototype_report, &mut prototype_graph, &resolved_prototypes, + |phase| { + let runtime_phase = match phase { + VisualDependencyPhase::Wear => MissionLoadPhase::GraphVisualWears, + VisualDependencyPhase::Material => MissionLoadPhase::GraphVisualMaterials, + VisualDependencyPhase::Texture => MissionLoadPhase::GraphVisualTextures, + }; + if last_graph_visual_phase != Some(runtime_phase) { + record_load_phase(&mut trace, &mut on_phase, runtime_phase); + last_graph_visual_phase = Some(runtime_phase); + } + }, ); if !prototype_report.is_success() { return Err(EngineError::PrototypeGraph { -- cgit v1.2.3