Notifications: tree, parent and deletion
When _Notification is useful, how Parented differs from EnterTree and why not to simulate lifecycle events.
Prefer a dedicated callback when available
For entry, readiness, frames and drawing, _EnterTree, _Ready, _Process and _Draw are usually clearer. _Notification(int what) is useful for a notification without a convenient dedicated callback or a custom notification protocol. Use SDK constant names instead of remembered numbers.
| Notification | Event |
|---|---|
| NotificationParented | A parent was assigned; the entire hierarchy may still be outside the active game |
| NotificationUnparented | A parent was removed; this alone is not native object deletion |
| NotificationPredelete | The engine is freeing the native object |
| NotificationReady | Readiness in the Entity protocol; normally use _Ready |
Observe real events
Run LifecycleDemo from the lifecycle guide. Both complete files are included here for copying. Journal contains parented/unparented alongside enter/ready/exit; native release adds predelete.
LifecycleProbe.cs
using System.Collections.Generic;
using Reckfell;
public partial class LifecycleProbe : Entity
{
public List<string> Journal { get; set; } = new();
public int Entries { get; private set; }
public int ReadyCalls { get; private set; }
public int Exits { get; private set; }
private void Record(string stage) => Journal.Add(Name + ":" + stage);
public override void _EnterTree() { Entries++; Record("enter"); }
public override void _Ready() { ReadyCalls++; Record("ready"); }
public override void _ExitTree() { Exits++; Record("exit"); }
public override void _Notification(int what)
{
if (what == NotificationParented) Record("parented");
if (what == NotificationUnparented) Record("unparented");
if (what == NotificationPredelete) Record("predelete");
}
}LifecycleDemo.cs
using System.Collections.Generic;
using Reckfell;
public partial class LifecycleDemo : Entity
{
public List<string> Journal { get; } = new();
public LifecycleProbe ParentProbe { get; private set; } = null!;
public LifecycleProbe ChildProbe { get; private set; } = null!;
public override void _Ready()
{
ParentProbe = new LifecycleProbe { Name = "Parent", Journal = Journal };
ChildProbe = new LifecycleProbe { Name = "Child", Journal = Journal };
ParentProbe.AddChild(ChildProbe);
AddChild(ParentProbe);
RemoveChild(ParentProbe);
AddChild(ParentProbe);
RemoveChild(ParentProbe);
ChildProbe.RequestReady();
AddChild(ParentProbe);
ReckfellApi.Print(string.Join(" → ", Journal));
ReckfellApi.Print("Ready calls: Parent=" + ParentProbe.ReadyCalls + ", Child=" + ChildProbe.ReadyCalls);
}
}AddChild to a detached parent already sends Parented to its child, but does not join EntityTree or call _EnterTree. RemoveChild from that hierarchy sends Unparented without _ExitTree because no active-tree entry occurred. The fixture tests these cases rather than inferring behavior from notification names.
Predelete is not a C# finalizer and makes no guarantee about garbage-collector timing. The checked bridge skips Predelete for C# RefCounted scripts: do not use that callback as a guaranteed Resource cleanup hook. The example above concerns Entity. Manage ordinary Entity native lifetime through the tree, QueueFree/Free and explicit ownership of detached objects. Disconnect gameplay handlers in _ExitTree: an object can leave a level and stay alive in a cache.
A custom notification
In the group example, GroupTarget2D declares RefreshNotification = 10001. NotifyGroup delivers that value to _Notification. It is this example custom protocol value; check for collisions in your own project.
Notification is not a signal carrying arbitrary arguments: the handler receives what. Do not send system NotificationEnterTree/Ready values to imitate attachment. Actual AddChild/RemoveChild also update the tree, world, input and groups; one notification number does not replace that work.