# Asset System Technical Design Initial design of the main interfaces and how that can be translated to the Python API. This design is complemented by the [Data Storage, Reading & UI Access](https://hackmd.io/@blender-asset-browser/rJTXlZT7u) document. ## C++ Mockup The highest level entity is the Asset System and provides basic functionality with global effect. ```cpp= using AssetListReceiver = void (*)(AssetRepresentation asset, // For progress report, like "this is number 5 of the 10 assets // available". Note that BOTH can increase over time, for example // when more results are found, `total_asset_count` can increase. size_t total_asset_count, size_t asset_index); /** AssetSystem manages multiple asset libraries. */ class AssetSystem { public: void register_library(AssetLibrary library); void set_active_library(AssetLibrary library); AssetLibrary get_active_library(); // Query the available assets of the active library that match the given // filter. void available_assets(AssetFilter filter, AssetListReceiver receiver); }; ``` The `AssetListReceiver` and `available_assets()` part may be superseded by the [asset storage design](https://hackmd.io/@blender-asset-browser/rJTXlZT7u). In there the storage is managed through `AssetList` and `AssetListStorage` (better separation of concerns). `AssetSystem` can be a mere interface. ```cpp= /** * AssetIdentifier contains enough information to find the AssetLibrary that * contains it, and for that library to load the asset. */ class AssetIdentifier { public: // URIs are one example of suitable identifiers, for example: // cloud://cloud.blender.org/project/asset/file.jpg // file:///path/to/project/asset/file.blend/Actions/MyPose // smb://nas.mystudio/assets/file.blend/Objects/SuperSintel static AssetIdentifier from_uri(std::string_view uri); std::string as_uri() const; }; ``` URIs seem quite interesting, but we need to be careful. Relative vs. absolute paths are a sensitive topic. Storing system dependent paths is a possible source of trouble when sharing files. Better to rely on it as little as possible. Needs to be thought trough well. \ It may make sense to let asset management add-ons opt-out of URIs and use custom identifiers. The identifier could be just an abstract class with a purely virtual comparison operator. ```cpp= using AssetReceiver = void (*)(AssetRepresentation asset); using AssetErrorCallback = void (*)(); // TBD signature /** * AssetLibrary manages a single library. This is just for information about * the library. The actual storage of assets is handled by #AssetList, and the * global #AssetListStorage. */ class AssetLibrary { // Expose the 'protocol://host' part supported by this library, so that // AssetIdentifiers can be matched to a library that supports it. std::string uri_protocol() const; std::string uri_host() const; // can be empty to indicate "any host" // Unsure whether this should be per AssetLibrary or on the AssetSystem (or // both). void register_error_callback(AssetErrorCallback callback); // Fast, as it only needs metadata and not the asset itself. void load_asset_repr(AssetIdentifier identifier, AssetReceiver callback); // Loads the actual asset, so could take more time. enum class LoadType { LINK, APPEND, NOMAIN, }; void load_asset(AssetIdentifier identifier, LoadType load_type, AssetReceiver callback); }; ``` ```cpp= /** * AssetRepresentation represents the asset, and contains enough information to * show it in the UI (name, description, tags, preview, etc.). * * Information that takes longer to load, like previews, could be loaded * asynchronously and become available later. * * There could be several singletons with their own semantics, for example one * for 'data is still loading' or 'this could get expanded into several assets'. * * When the asset is loaded & available in memory, this also provides access to * it via the `as_id()` function. Not sure about this design choice, though. */ class AssetRepresentation { AssetIdentifier identifier; ID *as_id_datablock(); // Valid once actually loaded. /** * The preview-image for this asset, if available (local or ) */ PreviewImage *preview(); /** * Path relative to the containing asset library. The asset-library and * asset-list provide helpers to get the full path from this * #AssetRepresentation. */ string relative_path(); }; ``` We may want to differentiate between local and external assets here. `AssetRepresentation` could also be an (abstract) base class with `LocalAssetRepresentation` and `ExternalAssetRepresentation` as implementations. This class needs a handle for C and RNA. E.g. so that operators can get asset information from context. ```c= /** A handle as C alias. */ typedef struct AssetRepresentation * AssetHandle; ``` <details> <summary>Further considerations (click to expand)</summary><p> >Currently, the asset-view template needs a RNA collection property passed to work. Once the [`uiModelView` proposal](https://hackmd.io/@blender-asset-browser/rJTXlZT7u) is in, this may not be needed anymore. But if it is, there needs to be an RNA equivalent of the struct that inherits from `PropertyGroup` > >There could be a C-API for this as well, for example: >```c= >const char *ED_asset_handle_relative_path_get(); >``` ></p></details> ></br> ```cpp= /** * Contains information on how to filter the available assets. * For example by ID type, tag selection, or free-form text search. */ class AssetFilter { }; ``` ## Python API Most (but not all!) asset information is independent of the current file loaded. Exceptions are the _Current File_ and the planned _Current Project_ library. The Python API needs to work independent of `bpy.data`, but can do some interactions on it (e.g. after getting the ID of a local asset). Therefore, a new module might make sense. ```python= import asset_system def register(): asset_system.register_library(...) # Example usage def some_func(): from asset_system.types import AssetLibrary library: AssetLibrary = asset_system.find_library(some_identifier) library.do_stuff() ``` Although maybe it shoudn't be a standalone module, it could be `bpy.asset_system` instead.