BlendFileBlock.get to support accessing different items in the file-block (#92898)

Add an `array_index` parameter to `block.get(property_name)` to get a
specific item from an array.

Example:
```python
verts = self.bf.block_from_addr[verts_ptr]
assert verts.get(b"co") == [-1.0, -1.0, -1.0]  # index 0
assert verts.get(b"co", array_index=1) == [-1.0, -1.0, 1.0]
```

Reviewed-on: https://projects.blender.org/blender/blender-asset-tracer/pulls/92898
This commit is contained in:
Andrej730 2025-11-24 14:53:15 +01:00 committed by Sybren A. Stüvel
parent b1c4f5e116
commit c69612b264
3 changed files with 23 additions and 1 deletions

View File

@ -596,6 +596,7 @@ class BlendFileBlock:
null_terminated=True,
as_str=False,
return_field=False,
array_index=0,
) -> typing.Any:
"""Read a property and return the value.
@ -612,8 +613,20 @@ class BlendFileBlock:
(assumes UTF-8 encoding).
:param return_field: When True, returns tuple (dna.Field, value).
Otherwise just returns the value.
:param array_index: If the property is an array, this determines the
index of the returned item from that array. Also see
`blendfile.iterators.dynamic_array()` for iterating such arrays.
"""
self.bfile.fileobj.seek(self.file_offset, os.SEEK_SET)
file_offset = self.file_offset
if array_index:
if not (0 <= array_index < self.count):
raise IndexError(
"Invalid 'array_index' for file-block. "
f"Expected int value in range 0-{self.count - 1}, got {array_index}."
)
file_offset += array_index * self.dna_type.size
self.bfile.fileobj.seek(file_offset, os.SEEK_SET)
dna_struct = self.bfile.structs[self.sdna_index]
field, value = dna_struct.field_get(

View File

@ -81,6 +81,9 @@ def dynamic_array(block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]:
pointer. BAT interprets these as a single data block, making it hard to
access individual elements. This function divides the array into individual
blocks by creating modified copies of the original block.
See `some_block.get(b'name', array_index)` if you want to access elements by
index (instead of iterating).
"""
element_size = block.dna_type.size

View File

@ -46,6 +46,12 @@ class BlendFileBlockTest(AbstractBlendFileTest):
mname = mesh.get((b"id", b"name"), as_str=True)
self.assertEqual("MECube³", mname)
# Try to access different file-block items.
verts_ptr = mesh.get(b"mvert")
verts = self.bf.block_from_addr[verts_ptr]
assert verts.get(b"co") == [-1.0, -1.0, -1.0]
assert verts.get(b"co", array_index=1) == [-1.0, -1.0, 1.0]
def test_get_recursive_iter(self):
ob = self.bf.code_index[b"OB"][0]
assert isinstance(ob, blendfile.BlendFileBlock)