diff --git a/CHANGELOG.md b/CHANGELOG.md index c128c4e..096ce96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ changed functionality, fixed bugs). ## Version 1.1 (in development) - Add support for Shaman (https://gitlab.com/blender-institute/shaman) +- Add support for Alembic files referenced in linked-in libraries. ## Version 1.0 (2019-03-01) diff --git a/blender_asset_tracer/trace/__init__.py b/blender_asset_tracer/trace/__init__.py index 9623b46..c574f09 100644 --- a/blender_asset_tracer/trace/__init__.py +++ b/blender_asset_tracer/trace/__init__.py @@ -51,8 +51,17 @@ def deps(bfilepath: pathlib.Path, progress_cb: typing.Optional[progress.Callback if progress_cb: bi.progress_cb = progress_cb + # Remember which block usages we've reported already, without keeping the + # blocks themselves in memory. + seen_hashes = set() # type: typing.Set[int] + for block in asset_holding_blocks(bi.iter_blocks(bfile)): - yield from blocks2assets.iter_assets(block) + for block_usage in blocks2assets.iter_assets(block): + usage_hash = hash(block_usage) + if usage_hash in seen_hashes: + continue + seen_hashes.add(usage_hash) + yield block_usage def asset_holding_blocks(blocks: typing.Iterable[blendfile.BlendFileBlock]) \ diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index 32e59ea..d227679 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -67,10 +67,17 @@ def modifier_mesh_sequence_cache(ctx: ModifierContext, modifier: blendfile.Blend block_name: bytes) -> typing.Iterator[result.BlockUsage]: """Yield the Alembic file(s) used by this modifier""" cache_file = modifier.get_pointer(b'cache_file') - path, field = cache_file.get(b'filepath', return_field=True) + if cache_file is None: + return + is_sequence = bool(cache_file[b'is_sequence']) + cache_block_name = cache_file.id_name + assert cache_block_name is not None + + path, field = cache_file.get(b'filepath', return_field=True) yield result.BlockUsage(cache_file, path, path_full_field=field, - block_name=b'%s.cache_file' % block_name) + is_sequence=is_sequence, + block_name=cache_block_name) @mod_handler(cdefs.eModifierType_Ocean) diff --git a/tests/blendfiles/alembic-sequence-source.blend b/tests/blendfiles/alembic-sequence-source.blend new file mode 100644 index 0000000..29c3e43 Binary files /dev/null and b/tests/blendfiles/alembic-sequence-source.blend differ diff --git a/tests/blendfiles/alembic-sequence-user.blend b/tests/blendfiles/alembic-sequence-user.blend new file mode 100644 index 0000000..e890464 Binary files /dev/null and b/tests/blendfiles/alembic-sequence-user.blend differ diff --git a/tests/blendfiles/clothsim.030.abc b/tests/blendfiles/clothsim.030.abc new file mode 100644 index 0000000..24e53a0 Binary files /dev/null and b/tests/blendfiles/clothsim.030.abc differ diff --git a/tests/blendfiles/clothsim.031.abc b/tests/blendfiles/clothsim.031.abc new file mode 100644 index 0000000..97d8bb1 Binary files /dev/null and b/tests/blendfiles/clothsim.031.abc differ diff --git a/tests/blendfiles/clothsim.032.abc b/tests/blendfiles/clothsim.032.abc new file mode 100644 index 0000000..2b56aa7 Binary files /dev/null and b/tests/blendfiles/clothsim.032.abc differ diff --git a/tests/blendfiles/clothsim.033.abc b/tests/blendfiles/clothsim.033.abc new file mode 100644 index 0000000..8cc4888 Binary files /dev/null and b/tests/blendfiles/clothsim.033.abc differ diff --git a/tests/blendfiles/clothsim.034.abc b/tests/blendfiles/clothsim.034.abc new file mode 100644 index 0000000..2b1fe05 Binary files /dev/null and b/tests/blendfiles/clothsim.034.abc differ diff --git a/tests/blendfiles/clothsim.035.abc b/tests/blendfiles/clothsim.035.abc new file mode 100644 index 0000000..e52eae6 Binary files /dev/null and b/tests/blendfiles/clothsim.035.abc differ diff --git a/tests/test_tracer.py b/tests/test_tracer.py index 8cca681..f39eb44 100644 --- a/tests/test_tracer.py +++ b/tests/test_tracer.py @@ -87,6 +87,9 @@ class DepsTest(AbstractTracerTest): if not exp: # Don't leave empty sets in expects. del expects[dep.block_name] + elif exp is None: + self.assertIsNone(actual, msg='unexpected dependency of block %s' % dep.block_name) + del expects[dep.block_name] else: self.assertEqual(exp, actual, msg='for block %s' % dep.block_name) del expects[dep.block_name] @@ -151,6 +154,25 @@ class DepsTest(AbstractTracerTest): b'//clothsim.abc', False), }) + def test_alembic_sequence(self): + self.assert_deps('alembic-sequence-user.blend', { + b'CFclothsim_alembic': + Expect('CacheFile', 'filepath[1024]', None, None, b'//clothsim.030.abc', True), + }) + + # Test the filename expansion. + expected = [self.blendfiles / ('clothsim.%03d.abc' % num) + for num in range(30, 36)] + performed_test = False + for dep in trace.deps(self.blendfiles / 'alembic-sequence-user.blend'): + if dep.block_name != b'CFclothsim_alembic': + continue + + actual = list(dep.files()) + self.assertEqual(actual, expected) + performed_test = True + self.assertTrue(performed_test) + def test_block_mc(self): self.assert_deps('movieclip.blend', { b'MCvideo.mov': Expect('MovieClip', 'name[1024]', None, None,