aboutsummaryrefslogtreecommitdiff
path: root/crates/fparkan-prototype
diff options
context:
space:
mode:
Diffstat (limited to 'crates/fparkan-prototype')
-rw-r--r--crates/fparkan-prototype/src/lib.rs63
1 files changed, 57 insertions, 6 deletions
diff --git a/crates/fparkan-prototype/src/lib.rs b/crates/fparkan-prototype/src/lib.rs
index dece041..9d52b7f 100644
--- a/crates/fparkan-prototype/src/lib.rs
+++ b/crates/fparkan-prototype/src/lib.rs
@@ -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]