Migrating to the 2027.0 API

Explains how to update a Cinema 4D 2026 plugin so that it compiles with the 2027.0 SDK.

Overview

The 2027 SDK keeps the ABI of the 2026 SDK (see ABI Compatibility). Plugins compiled with the 2026 SDK do not have to be recompiled and will work in all releases of Cinema 4D 2027. This manual is only relevant when you want to compile your plugin sources with the 2027 SDK. The shared ABI only guarantees that binaries keep working, not that source code keeps compiling. The frameworks have changed in places where 2026 plugin code must be adapted. These changes are mostly small and the best way to find them is to compile your plugin against the 2027 SDK and to fix the errors one by one. The changes below have been derived by comparing the 2026 and 2027 SDK examples and by building the unmodified 2026 examples with the 2027 frameworks (MSVC and ClangCL, Windows x64). Not every change is exercised by the examples; changes that are only visible in the framework headers are marked as such.

Change Type Description
Project definitions Major Legacy projectdefinition.txt files can be converted once during CMake configuration, see Project Definitions.
iferr_ignore Major The macro no longer returns the value of the ignored Result and only accepts a const char* reason. This breaks most Alloc() implementations of the form NewObj(...) iferr_ignore(...), see Changes to iferr_ignore.
Asset type components Major The method AssetTypeInterface::GetAssetDataType has been renamed to DeprecatedGetAssetDataType, see Asset Type Components.
Asset API Major Several methods have been renamed, deprecated, or have changed their signature or return type, see Asset API.
Custom data types Major CustomDataTypeClass gained the method GetHashCode, see Custom Data Types.
Block initialization Minor Block can no longer be initialized from an initializer list, see Initializing Blocks.
Deprecations Minor Several methods are now deprecated and produce warnings, see Deprecations.
Compiler warnings Minor ClangCL treats implicit integer to float conversions as errors, and more MSVC warnings are reported, see Compiler Warnings.
Removed symbols Minor A few symbols have been removed or renamed, see Removed and Renamed Symbols.

Changes to iferr_ignore

In 2026, iferr_ignore("reason") was a macro which expanded to .UncheckedGetValue(). The reason was not used, and the macro returned the value of the Result it was applied to. In 2027, the macro expands to .IfErrIgnore("reason"), a method which only accepts a const char* and returns void. This has three consequences for existing code:

  • The result of iferr_ignore cannot be used anymore. Statements such as return NewObj(MyObject) iferr_ignore("..."); or auto ref = Foo::Create() iferr_ignore("..."); do not compile anymore.
  • The reason must be a plain string literal. A Maxon string literal such as "reason"_s does not compile anymore.
  • The second argument which was accepted by the old macro is not supported anymore.

The most common case are the Alloc() functions of plugin classes. NewObj returns a ResultMemT<T*>, and GetPointer() returns the contained pointer, which is nullptr when the allocation failed. This is what the previous code implicitly did, and what the 2027 SDK examples do:

// 2026
static NodeData* Alloc() { return NewObj(MyObject) iferr_ignore("Caller handles nullptr"); }
// 2027
static NodeData* Alloc() { return NewObj(MyObject).GetPointer(); }
#define NewObj(T,...)
Definition: newobj.h:115
#define iferr_ignore(...)
Ignores an error and continues with the execution.
Definition: resultbase.h:1736

When you need the value of a Result and cannot ignore a failure, handle the error explicitly with iferr or iferr_return. The MorphMixerObject example for instance used the value of a Create() call and now branches to its error handler:

// 2026
auto bf = maxon::UniqueRef<BaseFile>::Create() iferr_ignore("Error is handled manually");
if (!bf || !bf->Open(f))
goto error;
// 2027
iferr (auto bf = maxon::UniqueRef<BaseFile>::Create())
goto error;
if (!bf->Open(f))
goto error;
static MAXON_ATTRIBUTE_FORCE_INLINE ResultMemT< BaseRef > Create(ARGS &&... args)
Definition: baseref.h:230
static auto Create(ARGS &&... args)
Definition: apibase.h:3003
BaseRef< T, UniqueRefHandler > UniqueRef
Definition: baseref.h:942
#define iferr(...)
Definition: errorbase.h:388
The maxon namespace contains all declarations of the Maxon API.
Definition: autoweight.h:22

When the result is not used, only the string literal must be adapted:

// 2026
_points.CopyFrom(points) iferr_ignore("do not return any error inside the constructor"_s);
// 2027
_points.CopyFrom(points) iferr_ignore("do not return any error inside the constructor");
Note
As a temporary measure, you can define MAXON_IFERRIGNORE_LEGACY_HANDLING for your module (e.g., before including any header or as a compile definition) to restore the old behavior of iferr_ignore, i.e., that it returns the value of the Result. The reason must then still be a plain string literal. We recommend to migrate your code instead.

Asset Type Components

The asset type interface method AssetTypeInterface::GetAssetDataType has been renamed to DeprecatedGetAssetDataType and is marked as [[deprecated("will be removed without replacement")]]. The rename has been done with an annotation which binds the new name to the old method identifier, i.e., the interface is binary identical. But source code which implements the method under its old name does not compile anymore. This affects every component which implements an asset type, such as the preset asset type in the example.assets plugin. The source processor reports this as:

error : The function GetAssetDataType is not a method of one of the interfaces, but it is marked with MAXON_METHOD.
#define MAXON_METHOD
Definition: interfacebase.h:1020

You have two options. The 2027 version of the example.assets plugin simply removes the override from the declaration and the definition of the asset type component:

// 2026, remove both the declaration in the header ...
MAXON_METHOD const maxon::DataType& GetAssetDataType() const;
// ... and the definition in the source file.
MAXON_METHOD const maxon::DataType& DotsPresetAssetTypeImpl::GetAssetDataType() const
{
return DotsPresetAssetImpl::GetClass().GetDataType();
}
Definition: datatypebase.h:770

If you want to keep implementing the method, for example because your binary must also load in Cinema 4D 2026 where the method is still part of the interface, rename it instead:

// 2027
MAXON_METHOD const maxon::DataType& DeprecatedGetAssetDataType() const;
MAXON_METHOD const maxon::DataType& DotsPresetAssetTypeImpl::DeprecatedGetAssetDataType() const
{
return DotsPresetAssetImpl::GetClass().GetDataType();
}

Asset API

The following changes to the Asset API do not affect the SDK examples, except for the repository creation in example.assets which is shown in detail. They are visible in the framework headers (mostly assets.h, asset_databases.h, and urlassetrepository.h).

2026 2027
AssetTypeInterface::CopyWithEncryption Renamed to CopyWithProtection, signature unchanged (annotation bound).
Result<Tuple<Data, Bool>> AssetTypeInterface::ComputeMetaData Returns Result<Tuple<Data, AssetMetaDataInterface::KIND>> (annotation bound), see below.
AssetRepositoryInterface::CopyAsset(aid, source, addEncryption, overwrite) The old overload is now DeprecatedCopyAsset (annotation bound). The new CopyAsset(aid, source, addProtection, overwrite, encryption) has an additional optional CryptoKey argument; calls with up to four arguments still compile.
AssetInterface::CreateRepositoryFromUrl Deprecated, use UrlAssetRepositoryFactory::CreateStandardRepository, see below.
AssetRepositoryTypes::AssetDatabase, AssetRepositoryTypes::WatchFolder Deprecated, use the factories in UrlAssetRepositoryFactories.
AssetInterface::GetUserPrefsRepository returns const UpdatableAssetRepositoryRef& Returns const AssetRepositoryRef& (annotation bound).
UpdatableAssetRepositoryRef available through maxon/assets.h Only forward declared in maxon/assets.h. Include maxon/updatable_asset.h to use the type.
AssetDatabaseInterface::SetDatabases(const Block<AssetDatabaseStruct>&) Takes a const Block<const AssetDatabaseStruct>& (annotation bound).
URLFLAGS::ASSETREPOSITORYTYPE Replaced by URLFLAGS::ASSETREPOSITORYFACTORY. New is also URLFLAGS::ASSETREPOSITORYWRITABLE.
AddAssetDepencendyStruct::AddDependency(const AssetDescription&) Requires an additional ASSET_UPDATE_POLICY argument, there is no overload without it.
AssetMetaDataInterface::KIND::STORAGELOCATION_DB, _USER, _DERIVED, _MASK Removed. New are DERIVED_FALLBACK, USER_FALLBACK, and COPY_AS_PERSISTENT.
ComputeMetaData

The second tuple element is now a flag enum instead of a Bool. Return KIND::NONE where you returned false, KIND::DERIVED where you returned true and the value should be cached in memory, and KIND::PERSISTENT (or KIND::DERIVED | KIND::PERSISTENT) when the value should additionally be cached on disk.

// 2026
const maxon::AssetRepositoryRef& repository, const maxon::IdAndVersion& asset,
const maxon::AssetMetaData& meta, const maxon::InternedId& metaId) const;
// 2027
const maxon::AssetRepositoryRef& repository, const maxon::IdAndVersion& asset,
const maxon::AssetMetaData& meta, const maxon::InternedId& metaId) const;
Definition: datatypelib.h:32
Definition: resultbase.h:1045
Creating Repositories

AssetInterface::CreateRepositoryFromUrl has been deprecated in favor of the repository factories. The result of the factory is a UrlAssetRepositoryRef, which converts to an AssetRepositoryRef. Note that the arguments have been reordered and that their meaning has changed (e.g., derivedInPrefs is now derivedInRepository), so review each argument instead of just copying the old values. Also note that maxon/urlassetrepository.h now includes maxon/updatable_asset.h instead of maxon/assets.h.

// 2026
maxon::UpdatableAssetRepositoryRef repository = maxon::AssetInterface::CreateRepositoryFromUrl(
uuid, maxon::AssetRepositoryTypes::AssetDatabase(), bases, databaseUrl, true, true, true) iferr_return;
// 2027
maxon::AssetRepositoryRef repository = maxon::UrlAssetRepositoryFactory::CreateStandardRepository(
uuid, databaseUrl, true, false, bases, true) iferr_return;
static MAXON_METHOD Result< UpdatableAssetRepositoryRef > CreateRepositoryFromUrl(const Id &rid, const Class< AssetRepositoryRef > &repoType, const Block< const AssetRepositoryRef > &bases, const Url &url, Bool writable, Bool derivedInPrefs, Bool tempRepository, const BackgroundEntryTuple &backgroundJob=GetZeroRef< BackgroundEntryTuple >())
#define iferr_return
Definition: resultbase.h:1771
Undefined UpdatableAssetRepositoryRef

Code which only included maxon/assets.h and uses UpdatableAssetRepositoryRef fails with an error such as ‘uses undefined class 'maxon::UpdatableAssetRepositoryRef’. Includemaxon/updatable_asset.hor switch toAssetRepositoryRef`.

Custom Data Types

CustomDataTypeClass has a new virtual method GetHashCode(const CustomDataType*). When MAXON_API_ABI_VERSION is at least 2027000 the method is pure virtual. In the 2027 SDK the ABI version is still 2026000, so that the method has a default implementation which stops execution with a CriticalStop() when it is called. This means that your 2026 plugin compiles unchanged, but fails at runtime as soon as the hash of one of your custom data values is requested. The Dots custom data type in example.assets and the Hybrid custom data type in example.nodes have been updated to implement the method and you should do the same for all your custom data types:

// In the data type class declaration.
// In the data type class implementation.
{
const DotsData* const d = static_cast<const DotsData*>(data);
if (!d)
return 0;
return d->GetHashCode();
}
// The data type itself must provide the hash code, here with a hasher.
{
hasher.HashAndCombine(canvasSize);
hasher.HashAndCombine(points);
return hasher.Finalize();
}
Definition: hash.h:14
void HashAndCombine(const ARGS &... args)
Definition: hash.h:90
constexpr HashInt Finalize() const
Definition: hash.h:80
UInt HashInt
Definition: apibase.h:348
maxon::HashInt GetHashCode(const T &value)
Definition: compare.h:722
Base class for custom data types.
Definition: c4d_customdatatype.h:50

Initializing Blocks

Block has lost its implicit constructor from an initializer list. The following code which compiled in 2026 now fails with ‘cannot convert from 'initializer list’ to 'maxon::Block<const maxon::Float32>'`:

const maxon::Block<const maxon::Float32> inputBuffer { 0.1f, 0.2f, 0.5f, 0.6f };
Definition: block.h:417

For a local variable, store the values in an array and construct the block from that array, as the example.image plugin does now. For temporary function arguments, the new type maxon::TmpBlock can be used instead. It converts from initializer lists, but may only be used for temporary arguments, as it does not own its data:

// A block for a local variable needs backing storage.
const maxon::Float32 inputBufferValues[4] = { 0.1f, 0.2f, 0.5f, 0.6f };
const maxon::Block<const maxon::Float32> inputBuffer{inputBufferValues};
// A temporary block as a function argument.
void Func(const maxon::Block<const maxon::Int>& values);
Definition: block.h:1200
float Float32
32 bit floating point value (float)
Definition: apibase.h:190

Deprecations

The following APIs still compile but produce deprecation warnings (ClangCL) which you should fix. Some of these have been deprecated in the 2026 service releases (2026.2 and 2026.3), i.e., after the 2026.0.0 SDK, and might not yet be known to code written against it.

Deprecated Replacement
Opt<T>::GetValue() (since 2026.3) ToResult(), e.g., collection.FindValue(key).ToResult() iferr_return.
Opt<T>::GetValueOrNull() (since 2026.2) GetValueOrDefault().
Url::GetUrl() (since 2026.2) ToString(), e.g., url.ToString().
AccessedObjectsCallback::MayAccessDeprecated MayAccess2; pass CAMERA, TIME, or EXTERNAL in the masks when needed.
ViewportSelect::PickMaterial overload with pickedObject The overload without that parameter.
AssignCopyConvert AssignCopy.
Id::Init(const InternedId&) in apibaseid.h The assignment operator.
DIRECT_PORT in nodesystem.h EXPLICIT_PORT.
// 2026
const maxon::ColorProfile& profile = collection.FindValue(key).GetValue() iferr_return;
maxon::String message("Saved to: "_s + url.GetUrl());
// 2027
const maxon::ColorProfile& profile = collection.FindValue(key).ToResult() iferr_return;
maxon::String message("Saved to: "_s + url.ToString());
Definition: string.h:1287

Compiler Warnings

The warning configuration of the SDK has been tightened. The warnings below can surface as errors or warnings in code which compiled without them in 2026:

  • ClangCL: -Werror=implicit-int-float-conversion is now enabled, where 2026 muted the warning. An implicit conversion of an integer to a floating point value, e.g., 0.415 * 4 / cnt where cnt is an Int, is now an error. Make the conversion explicit: 0.415 * 4 / (Float)cnt. The -Wtautological-compare family and -Wpointer-bool-conversion are now also enabled.
  • MSVC: The warning C4244 (conversion with possible loss of data) is not muted anymore. For example g_random.Get01() > .5 ? 0.0 : 1.0 assigned to a float now produces a warning. Use float literals such as 0.0f.

Removed and Renamed Symbols

2026 2027
DrawRect<T>::GetBottomRigthPoint() in gfx_basictypes.h Renamed to GetBottomRightPoint(); the misspelled name does not exist anymore.
maxon::nodes::NODESPACE::DOCUMENTPATH in node_spaces.h No longer declared.
ASSET_MANAGER_SETTINGS::LIST_VIEW_ICON_SIZE_LEVEL and GRID_VIEW_ICON_SIZE_LEVEL (Int) in assetmanagerinterface.h Replaced by LIST_VIEW_ICON_SIZE and GRID_VIEW_ICON_SIZE, which are Float values in the range [0, 1] and use the same string identifiers.

Project Definitions

The 2027 SDK uses native CMakeLists.txt files instead of projectdefinition.txt files. You do not have to convert your old project definitions by hand: configure the 2027 SDK once with MAXON_MIGRATE_LEGACY_PROJECTS=ON and the SDK generates a project/CMakeLists.txt for each module which only has a projectdefinition.txt. Review the generated files before you rely on them. See Migrating from projectdefinition.txt for the procedure and its limitations.

When you have questions about migrating your code, contact us via the Maxon Developer Portal.