Load explicit component point lists
Docs Deploy / Build and Deploy MkDocs (push) Successful in 42s

This commit is contained in:
2026-10-11 22:38:53 +04:00
parent 2f0608c259
commit bb3ae9cc3a
3 changed files with 533 additions and 19 deletions
+57 -6
View File
@@ -111,6 +111,9 @@ pub struct EffectivePrototype {
/// state belongs to each component instance and must not alter shared
/// mesh/material cache identity.
pub control_resource: Option<ResourceKey>,
/// Explicit component point resource referenced by this prototype's
/// resolved `objects.rlb` registry inheritance chain, when present.
pub point_resource: Option<ResourceKey>,
}
/// Prototype resolution source.
@@ -1141,7 +1144,14 @@ fn resolve_archive_model(
let Some(mesh) = find_mesh_resource(repository, archive, model_key)? else {
return Ok(None);
};
Ok(Some(effective(model_key.clone(), mesh, source, None, None)))
Ok(Some(effective(
model_key.clone(),
mesh,
source,
None,
None,
None,
)))
}
fn resolve_objects_registry_model(
@@ -1165,6 +1175,7 @@ fn resolve_objects_registry_model(
return Ok(None);
};
let control_resource = resolve_explicit_control_resource(object_key, &refs)?;
let point_resource = resolve_explicit_point_resource(object_key, &refs)?;
let mut missing_mesh_refs = Vec::new();
for item in refs.iter().filter(|item| is_explicit_mesh_ref(item)) {
@@ -1175,6 +1186,7 @@ fn resolve_objects_registry_model(
cstr_bytes(&item.resource_raw),
source_type,
control_resource.clone(),
point_resource.clone(),
)? {
return Ok(Some(prototype));
}
@@ -1195,6 +1207,7 @@ fn resolve_objects_registry_model(
source_type,
dependencies: Vec::new(),
control_resource,
point_resource,
}))
}
@@ -1262,6 +1275,7 @@ fn resolve_object_ref_model(
model_name: &[u8],
source_type: Option<u32>,
control_resource: Option<ResourceKey>,
point_resource: Option<ResourceKey>,
) -> Result<Option<EffectivePrototype>, PrototypeError> {
let archive = normalized_path_from_name(&ResourceName(cstr_bytes(&item.archive_raw).to_vec()))?;
let Some(mesh) = find_mesh_resource(repository, &archive, &ResourceName(model_name.to_vec()))?
@@ -1274,6 +1288,7 @@ fn resolve_object_ref_model(
PrototypeSource::ObjectsRegistry,
source_type,
control_resource,
point_resource,
)))
}
@@ -1285,18 +1300,37 @@ fn is_explicit_control_ref(item: &ObjectRefRecord) -> bool {
has_extension_bytes(cstr_bytes(&item.resource_raw), b"ctl")
}
fn is_explicit_point_ref(item: &ObjectRefRecord) -> bool {
has_extension_bytes(cstr_bytes(&item.resource_raw), b"cpt")
}
fn resolve_explicit_control_resource(
requested: &ResourceName,
refs: &[ObjectRefRecord],
) -> Result<Option<ResourceKey>, PrototypeError> {
resolve_explicit_resource(requested, refs, is_explicit_control_ref, "control")
}
fn resolve_explicit_point_resource(
requested: &ResourceName,
refs: &[ObjectRefRecord],
) -> Result<Option<ResourceKey>, PrototypeError> {
resolve_explicit_resource(requested, refs, is_explicit_point_ref, "point")
}
fn resolve_explicit_resource(
requested: &ResourceName,
refs: &[ObjectRefRecord],
is_match: fn(&ObjectRefRecord) -> bool,
label: &str,
) -> Result<Option<ResourceKey>, PrototypeError> {
let mut resolved = Vec::new();
for item in refs.iter().filter(|item| is_explicit_control_ref(item)) {
for item in refs.iter().filter(|item| is_match(item)) {
let archive =
normalized_path_from_name(&ResourceName(cstr_bytes(&item.archive_raw).to_vec()))?;
let name = resource_name(cstr_bytes(&item.resource_raw));
// CTLD is an optional pose sidecar. Keep the exact registry reference
// here, then let asset preparation treat a missing archive/entry as an
// absent override while still rejecting a present malformed payload.
// Keep exact registry references; asset preparation decides how to
// handle an absent optional sidecar and validates present payloads.
let key = ResourceKey {
archive,
name,
@@ -1313,7 +1347,7 @@ fn resolve_explicit_control_resource(
0 => Ok(None),
1 => Ok(resolved.pop()),
_ => Err(PrototypeError::Resource(ResourceError::Format(format!(
"prototype {} has ambiguous explicit control resources: {}",
"prototype {} has ambiguous explicit {label} resources: {}",
String::from_utf8_lossy(&requested.0),
resolved
.iter()
@@ -1386,6 +1420,7 @@ fn effective(
source: PrototypeSource,
source_type: Option<u32>,
control_resource: Option<ResourceKey>,
point_resource: Option<ResourceKey>,
) -> EffectivePrototype {
EffectivePrototype {
key: PrototypeKey(requested),
@@ -1394,6 +1429,7 @@ fn effective(
source_type,
dependencies: vec![mesh],
control_resource,
point_resource,
}
}
@@ -2133,6 +2169,7 @@ mod tests {
b"parent_proto".as_slice(),
build_object_refs(&[
(b"static.rlb".as_slice(), b"parent_proto.msh".as_slice()),
(b"fortif.rlb".as_slice(), b"parent_proto.cpt".as_slice()),
(b"fortif.rlb".as_slice(), b"parent_proto.ctl".as_slice()),
])
.as_slice(),
@@ -2142,6 +2179,7 @@ mod tests {
build_object_refs(&[
(b"objects.rlb".as_slice(), b"parent_proto".as_slice()),
(b"fortif.rlb".as_slice(), b"child_proto.bas".as_slice()),
(b"fortif.rlb".as_slice(), b"parent_proto.cpt".as_slice()),
(b"fortif.rlb".as_slice(), b"parent_proto.ctl".as_slice()),
])
.as_slice(),
@@ -2162,6 +2200,7 @@ mod tests {
build_nres(&[
(b"child_proto.bas".as_slice(), b"base"),
(b"parent_proto.ctl".as_slice(), b"control"),
(b"parent_proto.cpt".as_slice(), b"points"),
])
.into_boxed_slice(),
),
@@ -2181,6 +2220,9 @@ mod tests {
let control = resolved.control_resource.expect("inherited explicit CTL");
assert_eq!(control.archive.as_str(), "fortif.rlb");
assert!(control.name.0.eq_ignore_ascii_case(b"parent_proto.ctl"));
let points = resolved.point_resource.expect("inherited explicit CPT");
assert_eq!(points.archive.as_str(), "fortif.rlb");
assert!(points.name.0.eq_ignore_ascii_case(b"parent_proto.cpt"));
}
#[test]
@@ -2200,6 +2242,10 @@ mod tests {
b"missing.rlb".as_slice(),
b"optional_control.ctl".as_slice(),
),
(
b"explicit_points.rlb".as_slice(),
b"other_points.cpt".as_slice(),
),
])
.as_slice(),
)])
@@ -2230,6 +2276,11 @@ mod tests {
assert_eq!(control.archive.as_str(), "missing.rlb");
assert_eq!(control.name, resource_name(b"optional_control.ctl"));
assert_eq!(control.type_id, None);
let points = resolved
.point_resource
.expect("preserve independent explicit CPT reference");
assert_eq!(points.archive.as_str(), "explicit_points.rlb");
assert_eq!(points.name, resource_name(b"other_points.cpt"));
}
#[test]