# 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.