reckfellENGINE

Object: registration, reflection and ownership

Current C++ implementation, C# boundary, properties, signals and lifetime.

On this page

This page explains the native Object model and its C# boundary. Object supplies engine reflection, properties, signals, metadata and notifications. It does not by itself supply transforms, rendering or a position in an Entity tree. In C# its wrapper is ReckfellObject; this is distinct from System.Object.

Declaration, registration and reflection

A native subclass uses RECKFELL_CLASS(Type, Parent). The current implementation creates/initializes ReckfellType metadata and the native class hierarchy, then integrates it with ClassDB. A C++ class declaration, registry exposure and construction permission are related but separate facts.

Native registrationMeaning
RECKFELL_REGISTER_CLASSRegisters an exposed class with its native creator, subject to build/class configuration.
RECKFELL_REGISTER_VIRTUAL_CLASSRegisters it with the virtual flag used by automatic editor/documentation creation. Do not equate that flag with a C++ abstract class or assume every explicit creation query must return false.
RECKFELL_REGISTER_ABSTRACT_CLASSExposes the class metadata without a normal creator. The tested CanvasItem exists but is not instantiable.
RECKFELL_REGISTER_INTERNAL_CLASSRegisters internal metadata without normal public exposure.
RECKFELL_REGISTER_RUNTIME_CLASSRegisters a creator and runtime-class flag. Editor placeholder handling means this is not simply “the type does not exist in the editor.”

RECKFELL_SOFT_CLASS supplies the softer Object integration without the full registration machinery of RECKFELL_CLASS. Choose the mode intentionally; do not copy registration macros from a different SDK or assume all classes appear in every build/export.

_bind_methods() registers the class API during class initialization. Bind methods with ClassDB::bind_method and D_METHOD, supply optional trailing defaults with DEFVAL, and keep argument order consistent. A method must be bound to participate in the corresponding dynamic API; merely declaring a C++ method is insufficient.

The native registry is not CLR reflection. A C# script attached to an Entity can have GetType().Name different from GetClass(); the checked script still reports native Entity and is not a ClassDB class under its managed script name. For current class-chain queries and safe native creation, use the complete helper in the inheritance guide.

Properties and dynamic access

A PropertyInfo describes type, native name, editor hint, hint text and usage flags. ADD_PROPERTY connects that metadata to bound getter/setter names. PROPERTY_USAGE_EDITOR controls editor exposure and PROPERTY_USAGE_STORAGE participates in storage; an editor-only property is not automatically saved. Default property usage combines ordinary editor/storage behavior, but formats and custom implementations still matter.

Hints guide the editor; they are not universal runtime validators. Validate/clamp in the setter when the value contract requires it. Bind enum types through VARIANT_ENUM_CAST and expose their values with the appropriate BIND_ENUM_CONSTANT/BIND_CONSTANT macros rather than assuming a C++ enum is automatically script-visible.

For C#, prefer the typed API when the type is known: Entity2D.Position is clearer than a string lookup. Use Get/Set, GetIndexed/SetIndexed or ClassDB property access for tools that genuinely inspect unknown objects. The checked native property is position, the bound setter is set_position, and position:x addresses a component through EntityPath. These names are not the C# wrapper's PascalCase spelling. ClassDB.ClassGetProperty/ClassSetProperty use the native property path, not script properties; use Object.Get/Set for the script path.

Class-level metadata describes the registered class. Object.GetPropertyList/GetMethodList can also reflect the instance/script context. Inspect exact metadata names and types; a list of bound methods is not a universal list of every special operation exposed by a language wrapper.

Dynamic native C++ properties use _get, _set and _get_property_list. The class macros provide their dispatch chain; do not turn these hooks into unrelated virtual overrides by analogy with a C# script. Return true only for a handled name. Keep the property list and accessors consistent, and notify the editor with notify_property_list_changed when the list changes. Multilevel dispatch matters: the current generated getter tries the derived handler before its parent, while the setter tries the parent first.

Signals and metadata

ADD_SIGNAL registers a class signal description. A connection supplies a Callable and flags; declaration alone does not invoke listeners. Normal signal emission invokes connected callbacks synchronously unless deferred behavior is selected. OneShot disconnects after its first delivery. Retain the same callable identity for IsConnected/Disconnect; do not replace a captured callback with an unrelated new lambda.

C# classes normally use their supported signal declarations/events; AddUserSignal is useful when an individual object needs a dynamically described signal. The checks add docs_ping, discover it through instance metadata, connect, emit, disconnect and verify OneShot. A runtime user signal is not a new ClassDB declaration for every object of that type.

Metadata is a separate named Variant map. SetMeta/GetMeta do not define a normal typed property or change the native class. Metadata keys must be valid identifiers; a leading underscore hides metadata from normal Inspector display, not from code.

SetMeta with Nil removes an entry. GetMeta on a missing key with no non-Nil default reports an error in this implementation. Check HasMeta first or pass an explicit useful fallback; passing Nil is not a silent missing-key probe. RemoveMeta is the explicit removal operation.

Ownership and delayed work

Object kindLifetime model
Non-RefCounted ObjectExplicit native ownership. In C++, allocate/free through the engine's matching mechanisms, such as memnew/memdelete.
EntityTree/explicit lifetime. Free destroys immediately; QueueFree schedules deletion. Parent-child destruction and scene serialization ownership are separate concepts.
RefCountedNative strong references control lifetime. Store native references in Ref<T>; do not manually memdelete an object still owned by Ref.
ResourceA RefCounted object with resource/loading/storage behavior, optionally associated with a path.

A Variant containing an Entity does not make it immortal. An ObjectID/instance ID lets you look up a live object without retaining an unchecked raw pointer, but does not keep it alive and is not a persistent save-file identity. The checks resolve a live ID, queue deletion, then confirm the ID no longer resolves. An object can be valid yet already queued for deletion.

For native delayed data, resolve ObjectDB::get_instance or Variant::get_validated_object when appropriate rather than trusting a stale Object pointer. Validate casts with Object::cast_to<T>; a failed cast yields null. Validity checks do not synchronize competing threads. For C# use IsInstanceValid and the appropriate typed cast, with the same lifetime distinction.

SetDeferred and CallDeferred enqueue work; they do not execute inline or promise exactly the next game frame. CallDeferred does not provide the eventual method result synchronously. Notifications are engine lifecycle dispatch, separate from signals and ordinary bound calls; use the supported native notification hook or C# _Notification with the relevant notification constants.

Resource paths, cache and storage

A resource path identifies a resource for loading/caching; it does not prove the contents are already saved. An in-memory Resource may have no path. Default ResourceLoader reuse can return a shared loaded object, while explicit cache modes such as Ignore can produce an independent load. The old rule “only one loaded instance per file” is therefore not a valid general constraint.

For native saving, the current argument order is ResourceSaver::save(resource, path); C# uses ResourceSaver.Save(resource, path). Use the appropriate current resource format, such as .rdata. External resource references and embedded subresources follow the format/save flags; saving one object is not automatic persistence of arbitrary runtime state.

The C++ registration/property/resource implementation above is source-reviewed, not a newly compiled engine module. The installed-runtime checks execute the C# factory, reflection, metadata, signal, deferred-call and lifetime cases. They do not cover every registration mode, resource-cache combination, concurrent lifetime race, editor UI or platform build.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.