test: realign stage 2 acceptance coverage
This commit is contained in:
@@ -255,7 +255,12 @@ fn prototype_inspect_json(
|
|||||||
textures: report.texture_resolved_count,
|
textures: report.texture_resolved_count,
|
||||||
lightmaps: report.lightmap_resolved_count,
|
lightmaps: report.lightmap_resolved_count,
|
||||||
is_success: report.is_success(),
|
is_success: report.is_success(),
|
||||||
failures: report.failures.iter().take(16).map(graph_failure_output).collect(),
|
failures: report
|
||||||
|
.failures
|
||||||
|
.iter()
|
||||||
|
.take(16)
|
||||||
|
.map(graph_failure_output)
|
||||||
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,9 +371,7 @@ fn serialize_json<T: Serialize>(value: &T) -> Result<String, String> {
|
|||||||
serde_json::to_string(value).map_err(|err| err.to_string())
|
serde_json::to_string(value).map_err(|err| err.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn graph_failure_output(
|
fn graph_failure_output(failure: &fparkan_prototype::PrototypeGraphFailure) -> GraphFailureOutput {
|
||||||
failure: &fparkan_prototype::PrototypeGraphFailure,
|
|
||||||
) -> GraphFailureOutput {
|
|
||||||
GraphFailureOutput {
|
GraphFailureOutput {
|
||||||
root_index: failure.root_index,
|
root_index: failure.root_index,
|
||||||
edge: prototype_graph_edge_label(failure.edge),
|
edge: prototype_graph_edge_label(failure.edge),
|
||||||
@@ -472,4 +475,36 @@ mod tests {
|
|||||||
"{\"schema_version\":\"fparkan-prototype-inspect-v1\",\"key\":\"root\",\"roots\":1,\"node_count\":0,\"edge_count\":0,\"prototype_requests\":1,\"resolved\":1,\"unit_references\":0,\"unit_components\":0,\"direct_references\":1,\"wear_requests\":0,\"wear\":0,\"materials\":0,\"textures\":0,\"lightmaps\":0,\"is_success\":true,\"failures\":[]}"
|
"{\"schema_version\":\"fparkan-prototype-inspect-v1\",\"key\":\"root\",\"roots\":1,\"node_count\":0,\"edge_count\":0,\"prototype_requests\":1,\"resolved\":1,\"unit_references\":0,\"unit_components\":0,\"direct_references\":1,\"wear_requests\":0,\"wear\":0,\"materials\":0,\"textures\":0,\"lightmaps\":0,\"is_success\":true,\"failures\":[]}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mission_graph_json_has_canonical_field_order() {
|
||||||
|
let json = serialize_json(&MissionGraphOutput {
|
||||||
|
schema_version: MISSION_GRAPH_SCHEMA,
|
||||||
|
mission: "MISSIONS/Autodemo.00/data.tma".to_string(),
|
||||||
|
objects: 2,
|
||||||
|
paths: 3,
|
||||||
|
clans: 4,
|
||||||
|
extras: 5,
|
||||||
|
roots: 6,
|
||||||
|
node_count: 7,
|
||||||
|
edge_count: 8,
|
||||||
|
direct_references: 9,
|
||||||
|
unit_references: 10,
|
||||||
|
unit_components: 11,
|
||||||
|
prototype_requests: 12,
|
||||||
|
wear_requests: 13,
|
||||||
|
wear: 14,
|
||||||
|
materials: 15,
|
||||||
|
textures: 16,
|
||||||
|
lightmaps: 17,
|
||||||
|
is_success: true,
|
||||||
|
failures: 0,
|
||||||
|
})
|
||||||
|
.expect("serialize");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
json,
|
||||||
|
"{\"schema_version\":\"fparkan-mission-graph-v1\",\"mission\":\"MISSIONS/Autodemo.00/data.tma\",\"objects\":2,\"paths\":3,\"clans\":4,\"extras\":5,\"roots\":6,\"node_count\":7,\"edge_count\":8,\"direct_references\":9,\"unit_references\":10,\"unit_components\":11,\"prototype_requests\":12,\"wear_requests\":13,\"wear\":14,\"materials\":15,\"textures\":16,\"lightmaps\":17,\"is_success\":true,\"failures\":0}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -771,7 +771,11 @@ pub fn extend_graph_report_with_visual_dependencies<R: ResourceRepository>(
|
|||||||
wear_node_id,
|
wear_node_id,
|
||||||
fparkan_prototype::PrototypeGraphEdgeKind::MeshToWear,
|
fparkan_prototype::PrototypeGraphEdgeKind::MeshToWear,
|
||||||
PrototypeGraphRequiredness::Required,
|
PrototypeGraphRequiredness::Required,
|
||||||
Some(provenance_for_resource(root_index, mesh_parent_edge, &wear_key)),
|
Some(provenance_for_resource(
|
||||||
|
root_index,
|
||||||
|
mesh_parent_edge,
|
||||||
|
&wear_key,
|
||||||
|
)),
|
||||||
&mut next_edge,
|
&mut next_edge,
|
||||||
);
|
);
|
||||||
report.material_slot_count += table.entries.len();
|
report.material_slot_count += table.entries.len();
|
||||||
@@ -937,7 +941,9 @@ fn push_graph_resource_node(
|
|||||||
*next_node = (*next_node).saturating_add(1);
|
*next_node = (*next_node).saturating_add(1);
|
||||||
graph
|
graph
|
||||||
.nodes
|
.nodes
|
||||||
.push(fparkan_prototype::PrototypeGraphNode::resource(kind, resource, id));
|
.push(fparkan_prototype::PrototypeGraphNode::resource(
|
||||||
|
kind, resource, id,
|
||||||
|
));
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,14 +958,16 @@ fn push_graph_edge(
|
|||||||
) -> fparkan_prototype::PrototypeGraphEdgeId {
|
) -> fparkan_prototype::PrototypeGraphEdgeId {
|
||||||
let id = fparkan_prototype::PrototypeGraphEdgeId(*next_edge);
|
let id = fparkan_prototype::PrototypeGraphEdgeId(*next_edge);
|
||||||
*next_edge = (*next_edge).saturating_add(1);
|
*next_edge = (*next_edge).saturating_add(1);
|
||||||
graph.edges.push(fparkan_prototype::PrototypeGraphEdgeInstance {
|
graph
|
||||||
id,
|
.edges
|
||||||
from,
|
.push(fparkan_prototype::PrototypeGraphEdgeInstance {
|
||||||
to,
|
id,
|
||||||
kind,
|
from,
|
||||||
requiredness,
|
to,
|
||||||
provenance,
|
kind,
|
||||||
});
|
requiredness,
|
||||||
|
provenance,
|
||||||
|
});
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,11 +1152,8 @@ fn prepare_visual_with_repository_internal<R: ResourceRepository>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
for texture in texture_requests {
|
for texture in texture_requests {
|
||||||
let prepared_texture = prepare_texture(
|
let prepared_texture =
|
||||||
repository,
|
prepare_texture(repository, &texture, PreparedTextureUsage::Diffuse)?;
|
||||||
&texture,
|
|
||||||
PreparedTextureUsage::Diffuse,
|
|
||||||
)?;
|
|
||||||
texture_ids.push(prepared_texture.id);
|
texture_ids.push(prepared_texture.id);
|
||||||
prepared_textures.push(prepared_texture);
|
prepared_textures.push(prepared_texture);
|
||||||
texture_count += 1;
|
texture_count += 1;
|
||||||
@@ -1664,7 +1669,10 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_ne!(stable_visual_id(&first), stable_visual_id(&second));
|
assert_ne!(stable_visual_id(&first), stable_visual_id(&second));
|
||||||
assert_ne!(prepared_visual_signature(&first), prepared_visual_signature(&second));
|
assert_ne!(
|
||||||
|
prepared_visual_signature(&first),
|
||||||
|
prepared_visual_signature(&second)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1780,6 +1788,222 @@ mod tests {
|
|||||||
assert!(report.failures.is_empty());
|
assert!(report.failures.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn graph_visual_dependency_edges_preserve_root_and_parent_provenance() {
|
||||||
|
let mesh_key = ResourceKey {
|
||||||
|
archive: parse_path("static.rlb").expect("archive"),
|
||||||
|
name: resource_name(b"tree.msh"),
|
||||||
|
type_id: Some(0x4853_454D),
|
||||||
|
};
|
||||||
|
let mat0 = mat0_with_texture(b"TEX_A");
|
||||||
|
let texm = texm_payload();
|
||||||
|
let lightmap_texm = texm_payload();
|
||||||
|
let repo = repository_with_archives_meta(&[
|
||||||
|
(
|
||||||
|
"static.rlb",
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"tree.wea",
|
||||||
|
payload: b"1\n0 MAT_A\n\nLIGHTMAPS\n1\n0 LM_A\n",
|
||||||
|
type_id: WEAR_KIND,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"material.lib",
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"MAT_A",
|
||||||
|
payload: &mat0,
|
||||||
|
type_id: MAT0_KIND,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
TEXTURES_ARCHIVE,
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"TEX_A",
|
||||||
|
payload: &texm,
|
||||||
|
type_id: 0,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
LIGHTMAP_ARCHIVE,
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"LM_A",
|
||||||
|
payload: &lightmap_texm,
|
||||||
|
type_id: 0,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
let prototype = EffectivePrototype {
|
||||||
|
key: fparkan_prototype::PrototypeKey(resource_name(b"tree")),
|
||||||
|
geometry: PrototypeGeometry::Mesh(mesh_key),
|
||||||
|
source: fparkan_prototype::PrototypeSource::DirectArchive,
|
||||||
|
dependencies: Vec::new(),
|
||||||
|
};
|
||||||
|
let mut graph = prototype_graph_for_mesh(&prototype);
|
||||||
|
let mut report = PrototypeGraphReport {
|
||||||
|
root_count: 1,
|
||||||
|
direct_reference_count: 1,
|
||||||
|
resolved_count: 1,
|
||||||
|
mesh_dependency_count: 1,
|
||||||
|
..PrototypeGraphReport::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
extend_graph_report_with_visual_dependencies(
|
||||||
|
&repo,
|
||||||
|
&mut report,
|
||||||
|
&mut graph,
|
||||||
|
std::slice::from_ref(&prototype),
|
||||||
|
);
|
||||||
|
|
||||||
|
let wear_edge = graph
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.find(|edge| edge.kind == fparkan_prototype::PrototypeGraphEdgeKind::MeshToWear)
|
||||||
|
.expect("wear edge");
|
||||||
|
let material_edge = graph
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.find(|edge| edge.kind == fparkan_prototype::PrototypeGraphEdgeKind::WearToMaterial)
|
||||||
|
.expect("material edge");
|
||||||
|
let texture_edge = graph
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.find(|edge| edge.kind == fparkan_prototype::PrototypeGraphEdgeKind::MaterialToTexture)
|
||||||
|
.expect("texture edge");
|
||||||
|
let lightmap_edge = graph
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.find(|edge| edge.kind == fparkan_prototype::PrototypeGraphEdgeKind::WearToLightmap)
|
||||||
|
.expect("lightmap edge");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wear_edge
|
||||||
|
.provenance
|
||||||
|
.as_ref()
|
||||||
|
.expect("wear provenance")
|
||||||
|
.parent_edge,
|
||||||
|
Some(fparkan_prototype::PrototypeGraphEdgeId(1))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
material_edge
|
||||||
|
.provenance
|
||||||
|
.as_ref()
|
||||||
|
.expect("material provenance")
|
||||||
|
.parent_edge,
|
||||||
|
Some(wear_edge.id)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
texture_edge
|
||||||
|
.provenance
|
||||||
|
.as_ref()
|
||||||
|
.expect("texture provenance")
|
||||||
|
.parent_edge,
|
||||||
|
Some(material_edge.id)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
lightmap_edge
|
||||||
|
.provenance
|
||||||
|
.as_ref()
|
||||||
|
.expect("lightmap provenance")
|
||||||
|
.parent_edge,
|
||||||
|
Some(wear_edge.id)
|
||||||
|
);
|
||||||
|
assert!(graph
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.filter_map(|edge| edge.provenance.as_ref())
|
||||||
|
.all(|provenance| provenance.root_index == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads() {
|
||||||
|
let mesh_key = ResourceKey {
|
||||||
|
archive: parse_path("static.rlb").expect("archive"),
|
||||||
|
name: resource_name(b"tree.msh"),
|
||||||
|
type_id: Some(0x4853_454D),
|
||||||
|
};
|
||||||
|
let msh = minimal_model_archive();
|
||||||
|
let mat0 = mat0_with_texture(b"TEX_A");
|
||||||
|
let texm = texm_payload();
|
||||||
|
let lightmap_texm = texm_payload();
|
||||||
|
let repo = repository_with_archives_meta(&[
|
||||||
|
(
|
||||||
|
"static.rlb",
|
||||||
|
&[
|
||||||
|
TestNresEntry {
|
||||||
|
name: b"tree.msh",
|
||||||
|
payload: &msh,
|
||||||
|
type_id: 0x4853_454D,
|
||||||
|
attr2: 0,
|
||||||
|
},
|
||||||
|
TestNresEntry {
|
||||||
|
name: b"tree.wea",
|
||||||
|
payload: b"1\n0 MAT_A\n\nLIGHTMAPS\n1\n0 LM_A\n",
|
||||||
|
type_id: WEAR_KIND,
|
||||||
|
attr2: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"material.lib",
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"MAT_A",
|
||||||
|
payload: &mat0,
|
||||||
|
type_id: MAT0_KIND,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
TEXTURES_ARCHIVE,
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"TEX_A",
|
||||||
|
payload: &texm,
|
||||||
|
type_id: 0,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
LIGHTMAP_ARCHIVE,
|
||||||
|
&[TestNresEntry {
|
||||||
|
name: b"LM_A",
|
||||||
|
payload: &lightmap_texm,
|
||||||
|
type_id: 0,
|
||||||
|
attr2: 0,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
let prototype = EffectivePrototype {
|
||||||
|
key: fparkan_prototype::PrototypeKey(resource_name(b"tree")),
|
||||||
|
geometry: PrototypeGeometry::Mesh(mesh_key),
|
||||||
|
source: fparkan_prototype::PrototypeSource::DirectArchive,
|
||||||
|
dependencies: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let assets = prepare_mission_assets_with_repository(
|
||||||
|
&repo,
|
||||||
|
std::slice::from_ref(&(0..1)),
|
||||||
|
std::slice::from_ref(&prototype),
|
||||||
|
)
|
||||||
|
.expect("prepared mission assets");
|
||||||
|
|
||||||
|
assert_eq!(assets.models.len(), 1);
|
||||||
|
assert_eq!(assets.wears.len(), 1);
|
||||||
|
assert_eq!(assets.materials.len(), 1);
|
||||||
|
assert_eq!(assets.textures.len(), 2);
|
||||||
|
assert_eq!(assets.visuals.len(), 1);
|
||||||
|
assert_eq!(assets.object_visuals, vec![vec![assets.visuals[0].id]]);
|
||||||
|
|
||||||
|
let visual = &assets.visuals[0];
|
||||||
|
assert_eq!(visual.model_id, Some(assets.models[0].id));
|
||||||
|
assert_eq!(visual.wear_id, Some(assets.wears[0].id));
|
||||||
|
assert_eq!(visual.material_ids, vec![assets.materials[0].id]);
|
||||||
|
assert_eq!(visual.texture_ids.len(), 1);
|
||||||
|
assert_eq!(visual.lightmap_ids.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn graph_report_uses_strict_texture_archive_policy() {
|
fn graph_report_uses_strict_texture_archive_policy() {
|
||||||
let mesh_key = ResourceKey {
|
let mesh_key = ResourceKey {
|
||||||
@@ -1843,7 +2067,10 @@ mod tests {
|
|||||||
assert_eq!(report.texture_request_count, 1);
|
assert_eq!(report.texture_request_count, 1);
|
||||||
assert_eq!(report.texture_resolved_count, 0);
|
assert_eq!(report.texture_resolved_count, 0);
|
||||||
assert_eq!(report.failures.len(), 1);
|
assert_eq!(report.failures.len(), 1);
|
||||||
assert_eq!(report.failures[0].edge, PrototypeGraphEdge::MaterialToTexture);
|
assert_eq!(
|
||||||
|
report.failures[0].edge,
|
||||||
|
PrototypeGraphEdge::MaterialToTexture
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1937,7 +2164,10 @@ mod tests {
|
|||||||
let mut vfs = MemoryVfs::default();
|
let mut vfs = MemoryVfs::default();
|
||||||
for (archive, entries) in archives {
|
for (archive, entries) in archives {
|
||||||
let path = parse_path(archive).expect("archive path");
|
let path = parse_path(archive).expect("archive path");
|
||||||
vfs.insert(path, Arc::from(build_nres_with_meta(entries).into_boxed_slice()));
|
vfs.insert(
|
||||||
|
path,
|
||||||
|
Arc::from(build_nres_with_meta(entries).into_boxed_slice()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
CachedResourceRepository::new(Arc::new(vfs))
|
CachedResourceRepository::new(Arc::new(vfs))
|
||||||
}
|
}
|
||||||
@@ -1964,6 +2194,81 @@ mod tests {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn minimal_model_archive() -> Vec<u8> {
|
||||||
|
struct MshEntry<'a> {
|
||||||
|
type_id: u32,
|
||||||
|
attr3: u32,
|
||||||
|
name: &'a [u8],
|
||||||
|
payload: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
let entries = [
|
||||||
|
MshEntry {
|
||||||
|
type_id: 1,
|
||||||
|
attr3: 38,
|
||||||
|
name: b"Res1",
|
||||||
|
payload: &[],
|
||||||
|
},
|
||||||
|
MshEntry {
|
||||||
|
type_id: 2,
|
||||||
|
attr3: 0,
|
||||||
|
name: b"Res2",
|
||||||
|
payload: &[0; 0x8c],
|
||||||
|
},
|
||||||
|
MshEntry {
|
||||||
|
type_id: 3,
|
||||||
|
attr3: 0,
|
||||||
|
name: b"Res3",
|
||||||
|
payload: &[],
|
||||||
|
},
|
||||||
|
MshEntry {
|
||||||
|
type_id: 6,
|
||||||
|
attr3: 0,
|
||||||
|
name: b"Res6",
|
||||||
|
payload: &[],
|
||||||
|
},
|
||||||
|
MshEntry {
|
||||||
|
type_id: 13,
|
||||||
|
attr3: 0,
|
||||||
|
name: b"Res13",
|
||||||
|
payload: &[],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut out = vec![0; 16];
|
||||||
|
let mut offsets = Vec::with_capacity(entries.len());
|
||||||
|
for entry in &entries {
|
||||||
|
offsets.push(u32::try_from(out.len()).expect("offset"));
|
||||||
|
out.extend_from_slice(entry.payload);
|
||||||
|
let padding = (8 - (out.len() % 8)) % 8;
|
||||||
|
out.resize(out.len() + padding, 0);
|
||||||
|
}
|
||||||
|
let mut order: Vec<usize> = (0..entries.len()).collect();
|
||||||
|
order.sort_by(|left, right| entries[*left].name.cmp(entries[*right].name));
|
||||||
|
for (idx, entry) in entries.iter().enumerate() {
|
||||||
|
push_u32(&mut out, entry.type_id);
|
||||||
|
push_u32(&mut out, 0);
|
||||||
|
push_u32(&mut out, 0);
|
||||||
|
push_u32(
|
||||||
|
&mut out,
|
||||||
|
u32::try_from(entry.payload.len()).expect("payload"),
|
||||||
|
);
|
||||||
|
push_u32(&mut out, entry.attr3);
|
||||||
|
let mut name_raw = [0; 36];
|
||||||
|
let len = name_raw.len().saturating_sub(1).min(entry.name.len());
|
||||||
|
name_raw[..len].copy_from_slice(&entry.name[..len]);
|
||||||
|
out.extend_from_slice(&name_raw);
|
||||||
|
push_u32(&mut out, offsets[idx]);
|
||||||
|
push_u32(&mut out, u32::try_from(order[idx]).expect("sort index"));
|
||||||
|
}
|
||||||
|
out[0..4].copy_from_slice(b"NRes");
|
||||||
|
out[4..8].copy_from_slice(&0x100_u32.to_le_bytes());
|
||||||
|
out[8..12].copy_from_slice(&u32::try_from(entries.len()).expect("count").to_le_bytes());
|
||||||
|
let total_size = u32::try_from(out.len()).expect("total size");
|
||||||
|
out[12..16].copy_from_slice(&total_size.to_le_bytes());
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
fn prototype_graph_for_mesh(prototype: &EffectivePrototype) -> PrototypeGraph {
|
fn prototype_graph_for_mesh(prototype: &EffectivePrototype) -> PrototypeGraph {
|
||||||
let root_node = fparkan_prototype::PrototypeGraphNode::root(
|
let root_node = fparkan_prototype::PrototypeGraphNode::root(
|
||||||
fparkan_prototype::PrototypeKey(prototype.key.0.clone()),
|
fparkan_prototype::PrototypeKey(prototype.key.0.clone()),
|
||||||
@@ -2055,7 +2360,10 @@ mod tests {
|
|||||||
push_u32(&mut out, entry.type_id);
|
push_u32(&mut out, entry.type_id);
|
||||||
push_u32(&mut out, 0);
|
push_u32(&mut out, 0);
|
||||||
push_u32(&mut out, entry.attr2);
|
push_u32(&mut out, entry.attr2);
|
||||||
push_u32(&mut out, u32::try_from(entry.payload.len()).expect("payload"));
|
push_u32(
|
||||||
|
&mut out,
|
||||||
|
u32::try_from(entry.payload.len()).expect("payload"),
|
||||||
|
);
|
||||||
push_u32(&mut out, 0);
|
push_u32(&mut out, 0);
|
||||||
let mut name_raw = [0; 36];
|
let mut name_raw = [0; 36];
|
||||||
let len = name_raw.len().saturating_sub(1).min(entry.name.len());
|
let len = name_raw.len().saturating_sub(1).min(entry.name.len());
|
||||||
|
|||||||
@@ -1114,6 +1114,50 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore = "requires local testdata corpus"]
|
||||||
|
fn selected_is_and_is2_missions_preserve_runtime_object_drafts() {
|
||||||
|
for case in [
|
||||||
|
("IS", "MISSIONS/Autodemo.00/data.tma"),
|
||||||
|
("IS2", "MISSIONS/Autodemo.00/data.tma"),
|
||||||
|
] {
|
||||||
|
let root = local_testdata_root(case.0);
|
||||||
|
let vfs: Arc<dyn Vfs> = Arc::new(DirectoryVfs::new(root));
|
||||||
|
let mut engine = create(
|
||||||
|
EngineConfig {
|
||||||
|
mode: EngineMode::Headless,
|
||||||
|
},
|
||||||
|
EngineServices::new(vfs),
|
||||||
|
)
|
||||||
|
.expect("engine");
|
||||||
|
let loaded = load_mission(
|
||||||
|
&mut engine,
|
||||||
|
MissionRequest {
|
||||||
|
key: case.1.to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("load mission");
|
||||||
|
let drafts = loaded_mission_object_drafts(&engine).expect("object drafts");
|
||||||
|
let assets = loaded_mission_assets(&engine).expect("mission assets");
|
||||||
|
|
||||||
|
assert_eq!(drafts.len(), loaded.object_count);
|
||||||
|
assert!(drafts.iter().any(|draft| !draft.visual_ids.is_empty()));
|
||||||
|
for (index, draft) in drafts.iter().enumerate() {
|
||||||
|
assert_eq!(
|
||||||
|
draft.original_id,
|
||||||
|
u32::try_from(index).ok().map(OriginalObjectId)
|
||||||
|
);
|
||||||
|
assert_eq!(draft.visual_ids, assets.visuals_for_object(index));
|
||||||
|
assert!(draft.position.iter().all(|component| component.is_finite()));
|
||||||
|
assert!(draft
|
||||||
|
.orientation_raw
|
||||||
|
.iter()
|
||||||
|
.all(|component| component.is_finite()));
|
||||||
|
assert!(draft.scale.iter().all(|component| component.is_finite()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "requires licensed corpus"]
|
#[ignore = "requires licensed corpus"]
|
||||||
fn licensed_corpora_load_all_mission_foundations() {
|
fn licensed_corpora_load_all_mission_foundations() {
|
||||||
@@ -1326,6 +1370,18 @@ mod tests {
|
|||||||
root
|
root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn local_testdata_root(name: &str) -> PathBuf {
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.join("../../testdata")
|
||||||
|
.join(name);
|
||||||
|
assert!(
|
||||||
|
root.is_dir(),
|
||||||
|
"local testdata root is missing: {}",
|
||||||
|
root.display()
|
||||||
|
);
|
||||||
|
root
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum DenyRule {
|
enum DenyRule {
|
||||||
Suffix(&'static str),
|
Suffix(&'static str),
|
||||||
|
|||||||
@@ -207,6 +207,17 @@ S2-GRAPH-003 covered cargo test -p fparkan-assets --offline repository_plan_dedu
|
|||||||
S2-GRAPH-004 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
|
S2-GRAPH-004 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
|
||||||
S2-GRAPH-005 covered cargo test -p fparkan-cli --offline prototype_graph_json_has_canonical_field_order
|
S2-GRAPH-005 covered cargo test -p fparkan-cli --offline prototype_graph_json_has_canonical_field_order
|
||||||
S2-GRAPH-006 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
|
S2-GRAPH-006 covered cargo test -p fparkan-prototype --offline graph_report_records_resolved_roots_and_failures
|
||||||
|
S2-GRAPH-EDGE-001 covered cargo test -p fparkan-assets --offline graph_materializes_visual_dependency_nodes_and_edges
|
||||||
|
S2-GRAPH-PROV-001 covered cargo test -p fparkan-assets --offline graph_visual_dependency_edges_preserve_root_and_parent_provenance
|
||||||
|
S2-UNIT-EMPTY-001 covered cargo test -p fparkan-prototype --offline empty_unit_dat_resolves_as_zero_component_root
|
||||||
|
S2-ASSET-MODEL-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
|
||||||
|
S2-ASSET-WEAR-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
|
||||||
|
S2-ASSET-MATERIAL-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
|
||||||
|
S2-ASSET-TEXM-001 covered cargo test -p fparkan-assets --offline prepare_single_visual_mission_assets_materialize_model_wear_material_and_texture_payloads
|
||||||
|
S2-RUNTIME-DRAFT-001 covered local testdata/IS and testdata/IS2; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
|
||||||
|
S2-CLI-JSON-001 covered cargo test -p fparkan-cli --offline prototype_graph_json_has_canonical_field_order mission_graph_json_has_canonical_field_order
|
||||||
|
S2-LICENSED-MISSION-P1-001 covered local testdata/IS; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
|
||||||
|
S2-LICENSED-MISSION-P2-001 covered local testdata/IS2; cargo test -p fparkan-runtime --offline -- --ignored selected_is_and_is2_missions_preserve_runtime_object_drafts
|
||||||
S2-PROP-001 covered cargo test -p fparkan-prototype --offline generated_acyclic_prototype_graph_resolves_deterministically
|
S2-PROP-001 covered cargo test -p fparkan-prototype --offline generated_acyclic_prototype_graph_resolves_deterministically
|
||||||
S2-FUZZ-001 covered cargo test -p fparkan-prototype --offline arbitrary_unit_and_registry_bytes_are_bounded_and_panic_free
|
S2-FUZZ-001 covered cargo test -p fparkan-prototype --offline arbitrary_unit_and_registry_bytes_are_bounded_and_panic_free
|
||||||
L3-P1-MSH-001 covered cargo test -p fparkan-msh --offline licensed_corpus_msh_assets_validate
|
L3-P1-MSH-001 covered cargo test -p fparkan-msh --offline licensed_corpus_msh_assets_validate
|
||||||
@@ -219,8 +230,8 @@ L3-P1-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_
|
|||||||
L3-P2-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_mat0_and_wear_parse
|
L3-P2-WEAR-001 covered cargo test -p fparkan-material --offline licensed_corpus_mat0_and_wear_parse
|
||||||
L3-P1-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
L3-P1-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
||||||
L3-P2-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
L3-P2-ASSET-001 covered cargo test -p fparkan-runtime --offline licensed_corpora_load_all_mission_foundations
|
||||||
L3-P1-CAPTURE-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
S2-PLANNING-CAPTURE-P1-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
L3-P2-CAPTURE-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
S2-PLANNING-CAPTURE-P2-001 covered cargo test -p fparkan-game --offline selected_is_and_is2_missions_produce_approved_render_captures
|
||||||
S3-WEAR-001 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
S3-WEAR-001 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
||||||
S3-WEAR-002 covered cargo test -p fparkan-material --offline wear_requires_declared_rows
|
S3-WEAR-002 covered cargo test -p fparkan-material --offline wear_requires_declared_rows
|
||||||
S3-WEAR-003 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
S3-WEAR-003 covered cargo test -p fparkan-material --offline wear_preserves_legacy_id_but_selects_by_index
|
||||||
@@ -271,15 +282,23 @@ S3-MAT-RESOLVE-002 covered cargo test -p fparkan-material --offline resolve_mate
|
|||||||
S3-MAT-RESOLVE-003 covered cargo test -p fparkan-material --offline resolve_material_uses_first_entry_only_after_missing_default
|
S3-MAT-RESOLVE-003 covered cargo test -p fparkan-material --offline resolve_material_uses_first_entry_only_after_missing_default
|
||||||
S3-MAT-RESOLVE-004 covered cargo test -p fparkan-material --offline resolve_material_empty_texture_means_untextured
|
S3-MAT-RESOLVE-004 covered cargo test -p fparkan-material --offline resolve_material_empty_texture_means_untextured
|
||||||
S3-MAT-RESOLVE-005 covered cargo test -p fparkan-material --offline resolve_material_without_lightmap_keeps_lightmap_absent
|
S3-MAT-RESOLVE-005 covered cargo test -p fparkan-material --offline resolve_material_without_lightmap_keeps_lightmap_absent
|
||||||
S3-RENDER-001 covered cargo test -p fparkan-render --offline one_snapshot_draw_produces_one_draw_command
|
S2-PLANNING-RENDER-001 covered cargo test -p fparkan-render --offline one_snapshot_draw_produces_one_draw_command
|
||||||
S3-RENDER-002 covered cargo test -p fparkan-render --offline material_index_maps_through_resolved_material_slots
|
S2-PLANNING-RENDER-002 covered cargo test -p fparkan-render --offline material_index_maps_through_resolved_material_slots
|
||||||
S3-RENDER-003 covered cargo test -p fparkan-render --offline node_transform_is_retained
|
S2-PLANNING-RENDER-003 covered cargo test -p fparkan-render --offline node_transform_is_retained
|
||||||
S3-RENDER-004 covered cargo test -p fparkan-render --offline command_order_uses_phase_then_stable_key
|
S2-PLANNING-RENDER-004 covered cargo test -p fparkan-render --offline command_order_uses_phase_then_stable_key
|
||||||
S3-RENDER-005 covered cargo test -p fparkan-render --offline command_capture_independent_of_snapshot_construction_order
|
S2-PLANNING-RENDER-005 covered cargo test -p fparkan-render --offline command_capture_independent_of_snapshot_construction_order
|
||||||
S3-RENDER-006 covered cargo test -p fparkan-render --offline invalid_range_returns_contextual_error
|
S2-PLANNING-RENDER-006 covered cargo test -p fparkan-render --offline invalid_range_returns_contextual_error
|
||||||
S3-RENDER-007 covered cargo test -p fparkan-render --offline capture_is_stable
|
S2-PLANNING-RENDER-007 covered cargo test -p fparkan-render --offline capture_is_stable
|
||||||
S3-RENDER-008 covered cargo test -p fparkan-render --offline recording_backend_stores_captures
|
S2-PLANNING-RENDER-008 covered cargo test -p fparkan-render --offline recording_backend_stores_captures
|
||||||
S3-RENDER-009 covered cargo xtask policy
|
S2-PLANNING-RENDER-009 covered cargo xtask policy
|
||||||
|
S3-VK-MESH-UPLOAD-001 blocked awaits Stage 3 Vulkan asset renderer and GPU upload path
|
||||||
|
S3-VK-TEXM-UPLOAD-001 blocked awaits Stage 3 Vulkan texture upload path
|
||||||
|
S3-VK-DESCRIPTOR-001 blocked awaits Stage 3 descriptor set contract implementation
|
||||||
|
S3-VK-PIPELINE-001 blocked awaits Stage 3 graphics pipeline key and cache implementation
|
||||||
|
S3-VK-DRAW-MODEL-001 blocked awaits Stage 3 real Vulkan indexed model draw path
|
||||||
|
S3-VK-DRAW-TERRAIN-001 blocked awaits Stage 3 terrain Vulkan draw path
|
||||||
|
S3-VK-PIXEL-CAPTURE-001 blocked awaits Stage 3 fixed-camera pixel capture approval flow
|
||||||
|
S3-VK-VALIDATION-001 blocked awaits Stage 3 validation-clean GPU frame execution
|
||||||
S3-GL-001 omitted permanent macOS Desktop GL 3.3 adapter is not implemented; historical CGL probe is retained as external evidence only
|
S3-GL-001 omitted permanent macOS Desktop GL 3.3 adapter is not implemented; historical CGL probe is retained as external evidence only
|
||||||
S3-GL-002 omitted outside the current macOS-focused goal scope; GLES2 remains documented for portable/non-macOS targets
|
S3-GL-002 omitted outside the current macOS-focused goal scope; GLES2 remains documented for portable/non-macOS targets
|
||||||
S3-GL-003 blocked legacy fparkan-render-gl adapter removed while Vulkan renderer path is being brought in as the stage-3 backend
|
S3-GL-003 blocked legacy fparkan-render-gl adapter removed while Vulkan renderer path is being brought in as the stage-3 backend
|
||||||
|
|||||||
|
@@ -192,6 +192,17 @@
|
|||||||
`S2-GRAPH-004`
|
`S2-GRAPH-004`
|
||||||
`S2-GRAPH-005`
|
`S2-GRAPH-005`
|
||||||
`S2-GRAPH-006`
|
`S2-GRAPH-006`
|
||||||
|
`S2-GRAPH-EDGE-001`
|
||||||
|
`S2-GRAPH-PROV-001`
|
||||||
|
`S2-UNIT-EMPTY-001`
|
||||||
|
`S2-ASSET-MODEL-001`
|
||||||
|
`S2-ASSET-WEAR-001`
|
||||||
|
`S2-ASSET-MATERIAL-001`
|
||||||
|
`S2-ASSET-TEXM-001`
|
||||||
|
`S2-RUNTIME-DRAFT-001`
|
||||||
|
`S2-CLI-JSON-001`
|
||||||
|
`S2-LICENSED-MISSION-P1-001`
|
||||||
|
`S2-LICENSED-MISSION-P2-001`
|
||||||
`S2-PROP-001`
|
`S2-PROP-001`
|
||||||
`S2-FUZZ-001`
|
`S2-FUZZ-001`
|
||||||
`L3-P1-MSH-001`
|
`L3-P1-MSH-001`
|
||||||
@@ -204,8 +215,8 @@
|
|||||||
`L3-P2-WEAR-001`
|
`L3-P2-WEAR-001`
|
||||||
`L3-P1-ASSET-001`
|
`L3-P1-ASSET-001`
|
||||||
`L3-P2-ASSET-001`
|
`L3-P2-ASSET-001`
|
||||||
`L3-P1-CAPTURE-001`
|
`S2-PLANNING-CAPTURE-P1-001`
|
||||||
`L3-P2-CAPTURE-001`
|
`S2-PLANNING-CAPTURE-P2-001`
|
||||||
`S3-WEAR-001`
|
`S3-WEAR-001`
|
||||||
`S3-WEAR-002`
|
`S3-WEAR-002`
|
||||||
`S3-WEAR-003`
|
`S3-WEAR-003`
|
||||||
@@ -256,15 +267,23 @@
|
|||||||
`S3-MAT-RESOLVE-003`
|
`S3-MAT-RESOLVE-003`
|
||||||
`S3-MAT-RESOLVE-004`
|
`S3-MAT-RESOLVE-004`
|
||||||
`S3-MAT-RESOLVE-005`
|
`S3-MAT-RESOLVE-005`
|
||||||
`S3-RENDER-001`
|
`S2-PLANNING-RENDER-001`
|
||||||
`S3-RENDER-002`
|
`S2-PLANNING-RENDER-002`
|
||||||
`S3-RENDER-003`
|
`S2-PLANNING-RENDER-003`
|
||||||
`S3-RENDER-004`
|
`S2-PLANNING-RENDER-004`
|
||||||
`S3-RENDER-005`
|
`S2-PLANNING-RENDER-005`
|
||||||
`S3-RENDER-006`
|
`S2-PLANNING-RENDER-006`
|
||||||
`S3-RENDER-007`
|
`S2-PLANNING-RENDER-007`
|
||||||
`S3-RENDER-008`
|
`S2-PLANNING-RENDER-008`
|
||||||
`S3-RENDER-009`
|
`S2-PLANNING-RENDER-009`
|
||||||
|
`S3-VK-MESH-UPLOAD-001`
|
||||||
|
`S3-VK-TEXM-UPLOAD-001`
|
||||||
|
`S3-VK-DESCRIPTOR-001`
|
||||||
|
`S3-VK-PIPELINE-001`
|
||||||
|
`S3-VK-DRAW-MODEL-001`
|
||||||
|
`S3-VK-DRAW-TERRAIN-001`
|
||||||
|
`S3-VK-PIXEL-CAPTURE-001`
|
||||||
|
`S3-VK-VALIDATION-001`
|
||||||
`S3-GL-001`
|
`S3-GL-001`
|
||||||
`S3-GL-002`
|
`S3-GL-002`
|
||||||
`S3-GL-003`
|
`S3-GL-003`
|
||||||
|
|||||||
Reference in New Issue
Block a user