Asset Databases

Access and manage asset databases that contain assets which are exposed by the Asset Browser.

Overview

Assets are organized in asset databases and multiple databases can be connected to a running Cinema 4D instance, where each database contains at least the metadata for its assets. Asset databases can also contain caches for their stored data as preview thumbnails and downloaded content. Databases can be added in the Asset Browser section of the Preferences dialog of Cinema 4D, mounting them into Cinema 4D, and making both their primary data, the delivered content, and the associated metadata available in the Asset Browser and Asset API. Asset databases can be enabled or disabled: A disabled database will not contribute its assets and their metadata to the pool of assets accessible by the Asset Browser, but it will still be visible as a mounted database in asset database overview in the Asset Browser and in the Asset Browser Preferences.

The logical interface for asset databases are asset repositories which provide access to assets stored within databases. Each asset in a repository has an identifier which makes it an addressable entity. Repositories can represent one or multiple databases and allow either read and write access or read access only. An asset repository can have multiple bases, which are references to other repositories, and thereby access content from these other repositories. Within such asset repository with bases an asset identifier can occur multiple times, once in the main repository and once in each of its bases. In search operations for such duplicate asset identifiers the main repository takes then precedence over the bases unless specified differently. Asset identifiers can also be duplicated over asset versions, as assets with different versions are all stored under the same asset identifier but a different version identifier. The only way to uniquely identify an asset is therefore by searching both for the asset identifier and version of an asset.

There are three important premade repositories provided by Cinema 4D which bundle up other repositories: The builtin repository which contains the assets that are built into Cinema 4D. The application repository which includes the former and contains most of the atomic assets as for example builtin node templates. And finally the user preferences repository, a common entry point for asset searches, which contains both the builtin and application repository, as well as the content of the asset database shipped with Cinema 4D in the form of objects, materials, scenes and more. Databases added by the user will also be part of the user preferences repository. Additionally, each Cinema 4D project can have its own dedicated repository which is being loaded and stored with that scene file.

Fig I: On the left the database settings of the Asset Browser in the Preferences of Cinema 4D, each of the added asset databases db_1, db_2, and db_3 is a directory on the local machine. On right the content of the directory of db_3, containing sub-directories for two file assets, the directories prefixed with file_, and one node template asset, the directory prefixed with net.maxon.neutron.op.primitive_. The remaining folders and files exist to describe the database itself. Adding an empty folder to the asset databases of Cinema 4D will create the necessary database description in that location.

Technical Overview

An asset database is represented by a AssetDatabaseStruct, containing the the Url of the database and if the database is active or not. The interface AssetDataBasesInterface provides the ability to mount and unmount databases, clear database caches, as well as to find repositories for a specific database. The databases shipped with Cinema 4D cannot be unmounted and are also not exposed as AssetDatabaseStruct instances. The logical interface to access assets in databases is AssetRepositoryInterface. It represents an asset repository which can wrap one or multiple asset databases and provides means to read, write and search for assets. Assets within an asset repository are represented as AssetDescriptionInterface references, containing all the metadata that describe an asset.

For asset access usually one of the larger application provided asset repositories is being used. Either the application repository or more often the user preferences repository which contains most of the asset content. They can be accessed with GetApplicationRepository and GetUserPrefsRepository. The application repository is read only, while the user preferences repository grants both read and write access to the asset descriptions managed by it.

Assets repositories can be searched with the methods AssetRepositoryInterface::FindAssets and AssetRepositoryInterface::FindLatestAsset. The former allows to search with complex search operations for a set of assets, while the latter searches for a singular asset with a known asset identifier. Assets can be stored in an asset repository with the method AssetRepositoryInterface::StoreAsset and erased with the method AssetRepositoryInterface::EraseAsset. Repositories also provide the ability to react to events that occur on them, as for example assets being stored, erased or updated. This is realized through Observables attached to an asset repository to which users can attach their observer delegates. When an event occurs on the repository the observable is related to, all its observer delegates will be called with the data relevant to the event; for example the old and new metadata on a metadata update event.

Fig II: On the left - A simplified physical view on an asset database. The database in this example is stored as a folder on the local machine with each asset being a child folder of the database root folder. On the right - A simplified logical view on an asset database as employed by asset repositories which can represent multiple physical databases.

Related Topics

Articles Asset API Provide content as reusable assets served with the Cinema 4D Asset Browser.
Entity Creation Explains the managed memory environment of the maxon API with interfaces and references.
Observables

Explains the concept of observables and observers, used to bind multiple delegates to an event.

Important API Entities AssetDataBasesInterface Provides means to access and handle asset databases.
AssetDatabaseStruct Represents an asset database over its Url and other attributes.
AssetRepositoryInterface Provides access to the assets of one or multiple asset databases wrapped by an asset repository.
AssetDescriptionInterface Represents an asset over its metadata in an asset repository.
AssetManagerInterface

Provides limited control over the Asset Manager.

SDK Plugins Asset API Examples

Showcases basic interactions with the Asset API to modify asset databases and their content.

Examples Add User Databases Add an asset database to the running Cinema 4D instance.
Remove User Databases Remove an asset database from the running Cinema 4D instance.
Activate User Databases Activate an asset database attached to the running Cinema 4D instance.
Deactivate User Databases Deactivate an asset database attached to the running Cinema 4D instance.
Access User Databases Access all user databases attached to the running Cinema 4D instance.
Create Repositories for User Databases Create repositories for specific user databases to speed up search operations.
Access Important Repositories Access the important builtin, application, user preferences and active document repositories.
Attach Observers to Repositories Attach observers to a repository to react to new assets being added or the metadata of assets being modified.
Detach Observers from Repositories Detach observers from a repository which previously have been attached.
Store Assets Store an asset instance in a repository.
Copy Assets Copy assets with all their data and metadata.
Erase Assets Permanently remove assets and their metadata from an asset database.
Perform Simple Asset Searches Perform simple search operations for one or multiple assets in an asset repository.
Perform Filtered Asset Searches Perform filtered search operations for a set of assets over their metadata attributes.
Perform Sorted Asset Searches Perform a search operation for a set of assets with the assets being sorted by their metadata attributes.

Examples

The examples shown here are all related to the "Databases" category in the Asset API Examples plugin. With the plugin you can run these examples to see their output. Each example shown here has a link bar at its bottom, linking to the code on GitHub, as well as to a calling context on GitHub. A calling context is a function which showcases how to gather the required inputs for that specific example and is targeted at users who want to know how to carry out a specific task in more detail. The context link is named "How to call this example ...".

Add User Databases

Adds an asset database to the running Cinema 4D instance.

If the given directory does contain already an asset database, the added database will wrap around this data. If not, the necessary data for a new database will be created within the given directory. If the given url is already mounted as a database, that database will be returned.

{
// Test the url for being a file system directory url. Asset databases can also be provided as
// zip files and HTTP(S) urls, the example would have to be adjusted if these cases should be
// included.
if (url.GetScheme().Compare(maxon::URLSCHEME_FILESYSTEM) != maxon::COMPARERESULT::EQUAL ||
url.IoDetect() != maxon::IODETECT::DIRECTORY)
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION, "Invalid directory url."_s);
// Wait for all databases to be fully loaded and then retrieve all user databases.
if (!loaded)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load databases."_s);
// Get the user databases.
// Iterate over the databases to check if a database with the given Url has already been added.
for (maxon::AssetDatabaseStruct& database : databaseCollection)
{
if (database._dbUrl.Compare(url) == maxon::COMPARERESULT::EQUAL)
{
// Ensure that the database is active.
database._active = true;
ApplicationOutput("Returning already attached database with the url: @", database._dbUrl);
return std::move(database);
}
}
// Create a new database, add it to the collection and mount the whole collection.
maxon::AssetDatabaseStruct newDatabase{ url, true, true };
databaseCollection.Append(newDatabase) iferr_return;
ApplicationOutput("Added new database with the url: @", url);
return newDatabase;
}
void EventAdd(EVENT eventflag=EVENT::NONE)
Bool GeIsMainThread()
static MAXON_METHOD Result< void > GetDatabases(const ValueReceiver< const AssetDatabaseStruct & > &entry)
static MAXON_METHOD Result< void > SetDatabases(const Block< AssetDatabaseStruct > &newDataBases)
static MAXON_METHOD Bool WaitForDatabaseLoading()
Definition: basearray.h:415
Definition: resultbase.h:766
Definition: url.h:942
bool Bool
boolean type, possible values are only false/true, 8 bit
Definition: apibase.h:195
@ EQUAL
result is equal
static constexpr LiteralId URLSCHEME_FILESYSTEM
Scheme identifier for generic file system access.
Definition: url.h:671
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:67
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
@ DIRECTORY
Url is a directory, you can use GetBrowseIterator to iterate through the children.
#define iferr_scope
Definition: resultbase.h:1389
#define iferr_return
Definition: resultbase.h:1524
Definition: asset_databases.h:19

Remove User Databases

Attempts to remove a user databases from of the running Cinema 4D instance.

Will raise an error if the given url is not a mounted database.

maxon::Result<void> RemoveDatabase(const maxon::Url& url)
{
// Wait for all databases to be fully loaded and then retrieve all user databases.
if (!loaded)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load databases."_s);
// Get the user databases.
if (databaseCollection.GetCount() == 0)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "No user databases found."_s);
for (maxon::Int i = 0; i < databaseCollection.GetCount(); i++)
{
// Found a matching database.
if (databaseCollection[i]._dbUrl.Compare(url) == maxon::COMPARERESULT::EQUAL)
{
// Remove the database from the collection and write the new state back.
databaseCollection.Erase(i) iferr_return;
ApplicationOutput("Removed database with the url: @", url);
return maxon::OK;
}
}
// A database with the given Url was not found.
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, FormatString("Could not find database with the url: @", url));
}
Py_ssize_t i
Definition: abstract.h:645
ResultPtr< T > Erase(Int position, Int eraseCnt=1)
Definition: basearray.h:1006
MAXON_ATTRIBUTE_FORCE_INLINE Int GetCount() const
Definition: basearray.h:585
Int64 Int
signed 32/64 bit int, size depends on the platform
Definition: apibase.h:202
return OK
Definition: apibase.h:2735
#define FormatString(...)
Definition: string.h:2168

Activate User Databases

Activates a user database to make its assets accessible.

Activated databases will appear as checked in the Asset Browser section of the Cinema 4D Preferences dialog and their assets will become available in the Asset Browser.

maxon::Result<void> ActivateDatabase(const maxon::Url& url)
{
// Wait for all databases to be fully loaded and then retrieve all user databases.
if (!loaded)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load databases."_s);
// Get the user databases.
if (databaseCollection.GetCount() == 0)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "No user databases found."_s);
for (maxon::Int i = 0; i < databaseCollection.GetCount(); i++)
{
// Found a matching database.
if (databaseCollection[i]._dbUrl.Compare(url) == maxon::COMPARERESULT::EQUAL)
{
if (databaseCollection[i]._active)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, FormatString(
"The database with the url @ is already active."_s, url));
// Activate the database from the collection and write the new state back.
databaseCollection[i]._active = true;
ApplicationOutput("The database with the url @ has been activated.", url);
return maxon::OK;
}
}
// A database with the given Url was not found.
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, FormatString("Could not find database with the url: @"_s, url));
}

Deactivate User Databases

Deactivates a user database to make its assets inaccessible.

Deactivated databases will appear as unchecked in the Asset Browser section of the Cinema 4D Preferences dialog and their assets will become unavailable in the Asset Browser.

maxon::Result<void> DeactivateDatabase(const maxon::Url& url)
{
// Wait for all databases to be fully loaded and then retrieve all user databases.
if (!loaded)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load databases."_s);
// Get the user databases.
if (databaseCollection.GetCount() == 0)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "No user databases found."_s);
for (maxon::Int i = 0; i < databaseCollection.GetCount(); i++)
{
// Found a matching database.
if (databaseCollection[i]._dbUrl.Compare(url) == maxon::COMPARERESULT::EQUAL)
{
if (!databaseCollection[i]._active)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, FormatString(
"The database with the url @ is already not active."_s, url));
// Activate the database from the collection and write the new state back.
databaseCollection[i]._active = false;
ApplicationOutput("The database with the url @ has been deactivated.", url);
return maxon::OK;
}
}
// A database with the given Url was not found.
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, FormatString("Could not find database with the url: @"_s, url));
}

Access User Databases

Accesses the data structures representing the user asset databases.

The accessed AssetDatabaseStruct instances only contain meta information about the user databases, not the content of these databases. See AccessImportantRepositories for how to access the repositories of the application databases.

maxon::Result<void> AccessUserDatabases(
{
// Wait for all databases to be fully loaded and then retrieve all user databases.
if (!loaded)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load databases."_s);
if (results.GetCount() == 0)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "No user databases found."_s);
for (maxon::AssetDatabaseStruct& database : results)
{
ApplicationOutput("Found asset database with the properties - url: @, active: @, builtin: @",
database._dbUrl, database._active, database._isBuiltin);
}
return maxon::OK;
}

Create Repositories for User Databases

Creates repositories for a passed collection of databases.

The function CreateRepositoryFromUrl used in this example can also be used to create a repository and its underlying database from scratch when the provided Url points to location where no database has been established yet. See Access User Databases for how to access the AssetDatabaseStruct instances for the user databases.

maxon::Result<void> CreateRepositories(
{
for (maxon::AssetDatabaseStruct database : databaseCollection)
{
// Skip over asset database that are not databases in a local folder, as they cannot be handled
// in this way. To access their content the user preferences repository must be used. See
// AccessImportantRepositories() for details.
if (database._dbUrl.IoDetect() != maxon::IODETECT::DIRECTORY)
continue;
// Create a unique identifier for the repository.
const maxon::BaseArray<Char> path = database._dbUrl.GetPath().GetCString() iferr_return;
const maxon::Char* prefix = path.GetFirst();
// Repositories can be composed out of other repositories which are called bases. In this case
// no bases are used to construct the repository. But with bases a repository for all user
// databases could be constructed for example. All users databases are included by default in
// the user preferences repository.
const maxon::Block<const maxon::AssetRepositoryRef> bases;
// Create the repository for that database. If the third argument, the database URL,
// would point to a directory where no database is being located, Cinema would create the
// necessary database structure.
maxon::UpdatableAssetRepositoryRef repository = maxon::AssetInterface::CreateRepositoryFromUrl(
uuid, maxon::AssetRepositoryTypes::AssetDatabase(), bases, database._dbUrl, true, true, true) iferr_return;
// Print out some properties of the newly created repository.
maxon::Id id = repository.GetId();
maxon::LanguageRef defaultLanguage = maxon::Resource::GetDefaultLanguage();
maxon::String name = repository.GetRepositoryName(defaultLanguage, true) iferr_return;
maxon::Bool isWriteable = repository.IsWritable();
"Built repository with the properties - name: @, id: @, isWriteable: @ for the url: @",
name, id, isWriteable, database._dbUrl);
results.Append(repository) iferr_return;
}
return maxon::OK;
}
const char const char * name
Definition: abstract.h:195
Definition: c4d_string.h:41
static MAXON_METHOD Result< Id > MakeUuid(const Char *prefix, Bool compact)
MAXON_ATTRIBUTE_FORCE_INLINE const T * GetFirst() const
Definition: basearray.h:1175
Definition: apibaseid.h:243
for(i=0;i< length;i++)
Definition: unicodeobject.h:61
maxon::Bool Bool
Definition: ge_sys_math.h:51
char Char
signed 8 bit character
Definition: apibase.h:198
The maxon namespace contains all declarations of the MAXON API.
Definition: autoweight.h:14

Access Important Repositories

Accesses the builtin, application, user preferences and active document repositories.

The user preferences repository plays a central role as it contains most of the content which is accessible with the Asset Browser and therefor the usual choice for searching for assets or adding assets when there is no dedicated user database available.

maxon::Result<void> AccessImportantRepositories(
{
// The non-writable application repository based on the built-in repository of Cinema 4D, it
// will contain assets like the application provided node templates.
maxon::AssetRepositoryRef applicationRepo = maxon::AssetInterface::GetApplicationRepository();
if (!applicationRepo)
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Could not retrieve application repository."_s);
// The writable user preferences repository, it contains the application repository, the asset
// database shipped with Cinema 4D and the user databases attached to the running instance.
maxon::AssetRepositoryRef userPrefsRepo = maxon::AssetInterface::GetUserPrefsRepository();
if (!userPrefsRepo)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not retrieve user repository."_s);
// The repository that is associated with the active document, passing true to will cause a
// repository to be created when it has not been created yet.
maxon::AssetRepositoryRef documentRepo = doc->GetSceneRepository(true) iferr_return;
if (!documentRepo)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not retrieve the document repository."_s);
// Print out some information for all the retrieved repositories.
for (maxon::AssetRepositoryRef repository : { applicationRepo, userPrefsRepo, documentRepo })
{
maxon::Id id = repository.GetId();
maxon::String name = repository.GetRepositoryName(maxon::Resource::GetDefaultLanguage(), true) iferr_return;
maxon::Bool isWriteable = repository.IsWritable();
maxon::String msg = "Repository with the properties - name: @, id: @, isWriteable: @"_s;
ApplicationOutput(msg, name, id, isWriteable);
}
return maxon::OK;
}
BaseDocument * GetActiveDocument()
Definition: c4d_basedocument.h:497
static MAXON_METHOD const UpdatableAssetRepositoryRef & GetUserPrefsRepository()
static MAXON_METHOD const AssetRepositoryRef & GetApplicationRepository()
static MAXON_METHOD LanguageRef GetDefaultLanguage()
Definition: string.h:1237
const char * doc
Definition: pyerrors.h:226
const char const char * msg
Definition: object.h:438

Attach Observers to Repositories

Attaches observers for both a new asset being created and new metadata being stored to the respective observables of the passed repository.

An Observable is an entity that invokes one or multiple delegate functions, called observers, when a specific event has occurred. This example attaches an observer to each of the observables ObservableAssetStored and ObservableMetaDataStored associated with an asset repository. The observers attached in this example only report the changes that have been carried out and do nothing else. There are more observables attached to an asset repository as shown here; with which asset deletion, update and download events can be caught among other things.

maxon::Result<void> AttachRepositoryObservers(const maxon::AssetRepositoryRef& repository,
{
// A lambda to repeat a string, e.g., repeat("-"_s, 3) -> "---"_s. It will be used by the metadata
// observer to print lines of characters.
auto repeat = [](maxon::String content, maxon::Int count) -> maxon::String
{
count += 1;
for (maxon::Int i = 0; i < count; i++)
result += content;
return result;
};
// Attach an observer to the ObservableAssetStored observable which is invoked when an asset has
// been added to the repository. The argument to AddObserver() could also be a delegate function,
// but it is usually more convenient to use lambdas as shown here. Note that an ObservableAsset-
// Stored event will also be followed by an ObservableMetaDataStored event, when the metadata is
// being set for the newly created asset by the Asset API.
maxon::FunctionBaseRef assetStoredFunc = repository.ObservableAssetStored(true).AddObserver(
[](const maxon::AssetDescription& newAsset) -> void
{
{
ApplicationOutput("Observer Error: @", err);
};
// Report on the asset #newAsset which has been added.
const maxon::LanguageRef language = maxon::Resource::GetCurrentLanguage();
const maxon::String assetName = newAsset.GetMetaString(
maxon::OBJECT::BASE::NAME, language) iferr_return;
const maxon::String msg = (
"An asset with the type '@', name '@', and id '@' has been added to the repository '@'."_s);
msg, newAsset.GetTypeId(), assetName, newAsset.GetId(), newAsset.GetRepositoryId());
}
// Store the function reference to the observer so that it can be later removed by the
// corresponding example that removes observers.
observerData.Insert("ObservableAssetStored"_s, assetStoredFunc) iferr_return;
ApplicationOutput("Attached observer '@' to ObservableAssetStored", assetStoredFunc);
// Attach an observer to the ObservableMetaDataStored observer which is invoked when the metadata
// of an asset has changed in the repository.
maxon::FunctionBaseRef metadataStoredFunc = repository.ObservableMetaDataStored(true).AddObserver(
[&repeat](const maxon::AssetDescription& asset, const maxon::InternedId& metaId,
const maxon::Data& newData) -> void
{
{
ApplicationOutput("Observer Error: @", err);
};
// Report on the metadata changes of the asset description #asset.
const maxon::LanguageRef language = maxon::Resource::GetCurrentLanguage();
const maxon::String assetName = asset.GetMetaString(
maxon::OBJECT::BASE::NAME, language) iferr_return;
// Two formating strings for printing a header and entry messages on metadata changes.
const maxon::String headerMsg = (
"The metadata entry '@' has changed for the asset '@' (id: @):\n"_s + repeat("="_s, 100));
const maxon::String entryMsg = "\t@: @\n"_s + repeat("-"_s, 100);
ApplicationOutput(headerMsg, metaId, assetName, asset.GetId());
ApplicationOutput(entryMsg, "Old", prevData);
ApplicationOutput(entryMsg, "New", newData);
}
// Store the function reference to the observer so that it can be later removed by the
// corresponding example that removes observers.
observerData.Insert("ObservableMetaDataStored"_s, metadataStoredFunc) iferr_return;
ApplicationOutput("Attached observer '@' to ObservableMetaDataStored", metadataStoredFunc);
return maxon::OK;
}
Py_ssize_t count
Definition: abstract.h:640
KIND
This enum defines flags for the kind of a meta data entry.
Definition: assets.h:231
Definition: datatypebase.h:1229
Definition: hashmap.h:1115
ResultRef< Entry > Insert(KEY &&key, const V &value, Bool &created=BoolLValue())
Definition: hashmap.h:1633
Definition: datatypelib.h:32
static MAXON_METHOD LanguageRef GetCurrentLanguage()
PyObject PyObject * result
Definition: abstract.h:43
enum PyUnicode_Kind kind
Definition: unicodeobject.h:669
#define iferr_scope_handler
Definition: resultbase.h:1407

Detach Observers from Repositories

Attempts to detach the observers qualified by the passed in observer data from the passed repository.

This example can only be understood in the context of the example Attach Observers to Repositories. It will attempt to remove the observers that have been attached by the other example from the respective observables.

maxon::Result<void> DetachRepositoryObservers(const maxon::AssetRepositoryRef& repository,
{
const maxon::String msg = (
"Removed observer '@' from the observable '@' attached to the repository '@'"_s);
maxon::FunctionBaseRef func;
// Attempt to remove the ObservableAssetStored observer that has been attached by the other
// example and remove its entry in the HashMap to reflect the new state.
key = "ObservableAssetStored"_s;
func = observerData.FindValue(key).GetValue() iferr_return;
repository.ObservableAssetStored(false).RemoveObserver(func);
observerData.Erase(key) iferr_return;
ApplicationOutput(msg, func, key, repository.GetId());
// Do the same for the ObservableMetaDataStored observer.
key = "ObservableMetaDataStored"_s;
func = observerData.FindValue(key).GetValue() iferr_return;
repository.ObservableMetaDataStored(false).RemoveObserver(func);
observerData.Erase(key) iferr_return;
ApplicationOutput(msg, func, key, repository.GetId());
return maxon::OK;
}
PyObject * key
Definition: abstract.h:289
Opt< V & > FindValue(const KEY &key)
Definition: hashmap.h:1368
ResultOk< void > Erase(const Entry *entry, Bool deleteEntry=true)
Definition: hashmap.h:1738
PyObject Py_tracefunc func
Definition: ceval.h:10

Store Assets

Stores an asset instance in a repository.

Assets can be stored in a repository with the method AssetRepositoryInterface::StoreAsset. But this form of creating and storing assets is usually only required for minor asset types as keywords, categories and custom third party asset types. The core asset types for scenes, materials, objects, nodes, and image and movie files have convenience functions which simplify the process of creating assets of that type and StoreAsset is not required in these cases. See Asset Types for more information on asset types and how to create and load them. The example shown here is identical to the example Create Category Assets in the asset types documentation.

const maxon::AssetRepositoryRef& repository, const maxon::String& name,
const maxon::Id& category)
{
if (name.IsEmpty())
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION, "Invalid category name."_s);
// Create and store a new category asset.
maxon::CategoryAsset categoryAsset = maxon::CategoryAssetInterface::Create() iferr_return;
maxon::Id categoryId = maxon::AssetInterface::MakeUuid("category", false) iferr_return;
maxon::AssetDescription assetDescription = repository.StoreAsset(
categoryId, categoryAsset) iferr_return;
// Set the category name.
maxon::LanguageRef language = maxon::Resource::GetCurrentLanguage();
assetDescription.StoreMetaString(maxon::OBJECT::BASE::NAME, name, language) iferr_return;
// Set the category of the asset when the category is not the empty id.
if (!category.IsEmpty())
{
}
ApplicationOutput("Created category asset with the id: '@'", assetDescription.GetId());
return assetDescription;
}
static MAXON_METHOD Result< void > SetAssetCategory(const AssetDescription &asset, const Id &category)
static MAXON_METHOD Result< CategoryAsset > Create()
OBJECT
Object mode.
Definition: lib_activeobjectmanager.h:2
#define NAME
Definition: token.h:14

Copy Assets

Copies the passed asset into the passed repository.

Attempts to derive a matching asset identifier prefix from the asset identifier of the asset to copy and modifies the name of the new asset to indicate that it has been copied.

maxon::Result<maxon::AssetDescription> CopyAsset(const maxon::AssetRepositoryRef& repository,
const maxon::AssetDescription& asset, const maxon::Id& categoryId)
{
// Attempt to determine the prefix of the old asset id. Doing this is optional.
const maxon::String oldAssetId = asset.GetId().ToString();
oldAssetId.Split("@"_s, true, parts) iferr_return;
if (parts.GetCount() < 2)
{
parts.Flush();
oldAssetId.Split("_"_s, true, parts) iferr_return;
}
const maxon::String prefixString = parts.GetCount() > 1 ? parts[0] : "generic"_s;
const maxon::BaseArray<maxon::Char> prefix = prefixString.GetCString() iferr_return;
// Create a new asset identifier for the asset.
prefix.GetFirst(), true) iferr_return;
// Create a copy of the asset in the passed repository.
const maxon::AssetDescription assetCopy = repository.CopyAsset(newAssetId, asset) iferr_return;
// Modify the name of the asset copy to indicate that it is a copy.
const maxon::LanguageRef currentLanguage = maxon::Resource::GetCurrentLanguage();
const maxon::String oldName = assetCopy.GetMetaString(
maxon::OBJECT::BASE::NAME, currentLanguage, ""_s) iferr_return;
assetCopy.StoreMetaString(
maxon::OBJECT::BASE::NAME, oldName + " (Copy)"_s, currentLanguage) iferr_return;
// Attach the copied asset to the new category.
if (categoryId.IsPopulated())
{
}
return assetCopy;
}
void Flush()
Deletes all elements, but doesn't free memory (calls destructors though).
Definition: basearray.h:570
auto Copy(ITERATOR first, SENTINEL sentinel, DEST_ITERATOR dest) -> Result< DEST_ITERATOR >
Definition: algorithms.h:309

Erase Assets

Removes the passed asset from the passed repository permanently.

const maxon::AssetRepositoryRef& repository, const maxon::AssetDescription& asset)
{
// Erase #asset in #repository, will raise an error when #asset is not part of #repository.
repository.EraseAsset(asset) iferr_return;
return maxon::OK;
}

Perform Simple Asset Searches

Performs a search operation for an asset by its type, id or version.

maxon::Result<void> SimpleAssetSearch(const maxon::AssetRepositoryRef& repository)
{
// In a simple asset search, the search can be narrowed down by the asset type, id and version.
// Passing in the empty id for any of these qualifiers will broaden the search in that respect.
// I.e., passing in the empty id for the type will return any asset type, passing in the empty
// id for the identifier will return assets with any identifier, and passing in the empty id for
// the version will return assets of any version.
//
// So, searching for example, searching with the arguments (type = maxon::Id(),
// aid=maxon::Id("123"_s), version=maxon::Id()) will return assets of any type or version that
// have the asset id "123". And the arguments (type = maxon::AssetTypes::File().GetId(),
// aid = maxon::Id(), version = maxon::Id()) will search for file type assets with any
// asset id and any version, i.e., it will retrieve all file assets. The asset version is also
// impacted by the ASSET_FIND_MODE as shown below.
// In a simple search the retrieved assets will be stored directly in a collection type.
// Search for all category assets with any id or version in #repository, but only retrieve
// the latest version of each asset. I.e., when there is a version 1.0 and 2.0 of an asset, only
// version 2.0 will be returned.
repository.FindAssets(maxon::AssetTypes::Category().GetId(), maxon::Id(), maxon::Id(),
"Found @ category assets in the repository @.", results.GetCount(), repository.GetId());
// The id of the "Toy Plane 01" asset in the "Objects/Toys" asset category.
maxon::Id assetId("file_565089079061675d");
// When searching for a singular asset with a single id, one can also use FindLatestAsset
// to directly return the AssetDescription.
maxon::AssetDescription asset = repository.FindLatestAsset(
maxon::AssetTypes::File(), assetId, maxon::Id(), maxon::ASSET_FIND_MODE::LATEST) iferr_return;
ApplicationOutput("Found the 'Toy Plane 01' asset: @", asset.GetId());
return maxon::OK;
}
@ LATEST
Set this flag to obtain only the latest version of the asset.

Perform Filtered Asset Searches

Performs a filtered search evaluating the metadata of the searched assets while searching.

Search operations can be filtered more granularly with a delegate passed for the value receiver of the search operation, allowing to in- or exclude assets from the search results over their metadata.

// This is a simple delegate function used by one of the search operations below. It will be called
// for each asset which is being iterated over and it simply appends all encountered assets to a
// global asset container.
maxon::Result<maxon::Bool> SimpleDelegate(const maxon::AssetDescription& asset)
{
g_delegate_asset_results.Append(asset) iferr_return;
return true;
}
maxon::Result<void> FilteredAssetSerach(const maxon::AssetRepositoryRef& repository)
{
// For more complex search operations a delegate can be passed as the argument #receiver to
// FindAssets(). In the example SimpleAssetSearch() a BaseArray took its place, but when
// the found assets should be filtered in more complex fashion, it must be replaced by an
// explicit delegate or a lambda.
// Searching for all file assets of subtype object with a lambda.
maxon::Bool didComplete = repository.FindAssets(
maxon::AssetTypes::File(), maxon::Id(), maxon::Id(), maxon::ASSET_FIND_MODE::LATEST,
// The last argument is the maxon::ValueReceiver, here we pass the lambda, it will be called
// for each encountered asset and must return true to continue the search or false to cancel
// it before all assets have been yielded.
[&results](const maxon::AssetDescription& asset) -> maxon::Result<maxon::Bool>
{
// Retrieve the asset subtype of the currently yielded asset. See the metadata examples for
// details on the asset metadata model.
maxon::AssetMetaData assetMetadata = asset.GetMetaData();
maxon::Id assetSubtype = assetMetadata.Get(
maxon::ASSETMETADATA::SubType, maxon::Id()) iferr_return;
// Append the asset to the results when it is of subtype object.
if (assetSubtype == maxon::ASSETMETADATA::SubType_ENUM_Object.GetId())
{
results.Append(asset) iferr_return;
}
// Returning false would stop the asset searching, which can be useful when looking for
// a specific asset.
return true;
}
// #didComplete would be false at this point when the ValueReceiver would have returned false
// at some point, terminating the search early.
ApplicationOutput("The search has been stopped: @", !didComplete);
ApplicationOutput("Found @ file type assets of subtype object.", results.GetCount());
// Instead of a lambada also a ValueReceiver wrapping a function can be passed. Here a search
// for all the latest keyword assets is performed and each asset it passed through the delegate.
g_delegate_asset_results.Flush();
maxon::ValueReceiver<const maxon::AssetDescription&> delegateFunction = SimpleDelegate;
repository.FindAssets(
maxon::AssetTypes::Keyword(), maxon::Id(), maxon::Id(), maxon::ASSET_FIND_MODE::LATEST,
delegateFunction) iferr_return;
"Delegate attached @ keyword assets to global asset array.", g_delegate_asset_results.GetCount());
return maxon::OK;
}
MAXON_ATTRIBUTE_FORCE_INLINE ResultRef< T > Append(ARG &&x)
Appends a new element at the end of the array and constructs it using the forwarded value.
Definition: basearray.h:628
Definition: delegate.h:240
const Id & Get() const
Definition: apibaseid.h:159

Perform Sorted Asset Searches

Performs a search operation for a set of assets with the assets being sorted by their name and version attributes.

The sorting is realized with the type SortedArray. This can technique can be combined with both the simple and filtered asset search approach. Shown here is only a sorted simple search, where a sorted array takes place of the value receiver.

maxon::Result<void> SortedAssetSearch(const maxon::AssetRepositoryRef& repository)
{
// When handling assets often a sorted list of assets is required. This can be accomplished by
// implementing a SortedArray which then can be passed as the #receiver of FindAssets().
// A SortedArray implementation for asset descriptions which sorts them by name and version.
class SortedAssetCollection :
public maxon::SortedArray<SortedAssetCollection, maxon::BaseArray<maxon::AssetDescription>>
{
public:
// Sorting operators
static Bool LessThan(const maxon::AssetDescription& a, const maxon::AssetDescription& b)
{
const maxon::String nameA = GetAssetName(a);
const maxon::String nameB = GetAssetName(b);
// Sort by name first, then by version.
if (nameA.Compare(nameB) == maxon::COMPARERESULT::EQUAL)
return a.GetVersion() < b.GetVersion();
return nameA.Compare(nameB) == maxon::COMPARERESULT::LESS;
}
static Bool IsEqual(const maxon::AssetDescription& a, const maxon::AssetDescription& b)
{
const maxon::Bool nameEqual = (
GetAssetName(a).Compare(GetAssetName(b)) == maxon::COMPARERESULT::EQUAL);
// Sort by name first, then by version.
if (nameEqual)
return a.GetVersion() == b.GetVersion();
return nameEqual;
}
private:
// Returns the name of an asset in the currently active language.
static const maxon::String GetAssetName(const maxon::AssetDescription& asset)
{
{
return ""_s;
};
maxon::String name = asset.GetMetaString(
maxon::OBJECT::BASE::NAME, maxon::Resource::GetCurrentLanguage(), ""_s) iferr_return;
return name;
}
};
// Find all sorted keyword assets.
SortedAssetCollection results;
repository.FindAssets(maxon::AssetTypes::Keyword(), maxon::Id(), maxon::Id(),
// Print the first ten sorted keywords assets.
maxon::Int count = results.GetCount() > 10 ? 9: results.GetCount() - 1;
ApplicationOutput("Displaying the first @ keyword assets sorted by name and version:", count);
for (maxon::Int i = 0; i < count; i++)
{
const maxon::AssetDescription asset = results[i];
const maxon::String name = asset.GetMetaString(
maxon::OBJECT::BASE::NAME, maxon::Resource::GetCurrentLanguage(), ""_s) iferr_return;
ApplicationOutput("@ (Version: @, Id: @)", name, asset.GetVersion(), asset.GetId());
}
return maxon::OK;
}
MAXON_ATTRIBUTE_FORCE_INLINE std::enable_if< maxon::IsCollection< COLLECTION2 >::value &&!STD_IS_REPLACEMENT(same, typename std::decay< COMPARE >::type, EQUALITY), Bool >::type IsEqual(const COLLECTION2 &other, COMPARE &&cmp=COMPARE()) const
Definition: collection.h:236
Definition: sortedarray.h:51
@ LESS
result is less than
Bool LessThan(UInt a1, UInt a2, UInt b1, UInt b2)
Definition: integer.h:151
@ ALL
Set this flag to obtain all versions of the asset.