Scene and entities
A level is a collection of objects. Each object is a bare identifier with a set of components attached to it: a transform, a mesh renderer, a physics body, whatever you have written yourself. Parent and child relationships are links between objects rather than one object containing another.
An object is a number, not a thing
Specifically it is a slot and a counter. Deleting an object advances the counter in that slot, so anything still holding the old number can be told it is stale rather than silently getting whatever moved in afterwards.
That matters as soon as you want undo. Restoring a deleted object as a new one would look correct in the scene tree and be wrong everywhere else, because every reference to it, and every later step in the undo history, holds the number it used to have.
So undoing a delete restores the same number. Undo works backwards through the history, which is what guarantees the slot is free by the time it gets there: anything created after the delete has already been undone. If the slot somehow is not free, the restore reports that rather than quietly filling a different object with the wrong components.
An object owns nothing
A widget in a user interface contains its children, so picking it up takes the whole branch with it. An object in a level does not:
- its components are stored elsewhere, grouped by type,
- its children are separate objects,
- its position among its siblings is something only the parent knows.
All three have to be recorded explicitly when something is deleted, or undo brings back an object that is missing half of what made it what it was.
Nothing changes the level directly
There is no path from a panel to the level that skips the undo history. The scene tree does not delete objects itself, the properties panel does not write values itself, and dragging a move handle in the viewport does not set a position itself.
The moment one of them does, that is the change undo does not know about.
This rule came from the interface designer, which had undo first, and moved across when the level got its own.
A level is a file
Lights, cameras, interface documents and control bindings are all data rather than code.
The file format is the definition of what a level is, which is why leaving play mode restores the level by saving and reloading it rather than by taking a snapshot in memory. Anything that survives being saved survives a play session, and anything that does not was never going to survive being reloaded either.
It also means the save and load path is exercised every time anyone presses play, which is far more testing than it would otherwise get.
If saving fails, play does not start. Entering a session you cannot leave is worse than not entering one.
How the engine knows what your types contain
Saving a file, showing an object in the properties panel, and carrying it across a code reload all need the same thing: a list of what fields a type has.
That list is generated from your source code at build time rather than written by hand. It sits behind a boundary on purpose, because a future version of C++ will work it out on its own, and switching to that should not require touching anything that uses it.