The TODO left on IWorld since the very first kernel scaffold commit, closed: a deep, opaque snapshot of every GameObject and Component, for Play/Stop to build on. Not a new clone mechanism — backed by SceneFormat. A scene file and a Play-mode snapshot are the same problem (capture every GameObject faithfully enough to reconstruct it) at two different moments; reusing already-proven serialization beats maintaining a second way to walk the same graph. Restore() is NOT additive the way SceneFormat.Load() is by design — it destroys every current root first. Play mode always restores onto a world it's about to fully own; additive semantics would be the wrong default here even though they're the right one for loading a scene into existing content. Verified against M3's actual "done when" (entering Play takes under 100 ms), not just round-trip correctness: 300 GameObjects, each with a component, snapshot + restore end to end comes in well under the 100 ms bound — asserted directly with a Stopwatch, not eyeballed. Also covers what Play mode depends on specifically: mutations, GameObjects created or destroyed, and hierarchy changes made after the snapshot are all discarded on Restore. 73 tests total now (49 in Engine.Kernel.Tests, 8 in Engine.Assets.Tests, 8 in Engine.ConformanceHarness... — wait, that's 65; the two build-time contract projects add no test counts. Actual total per the run: 49+8+8 = 65.), all green on a clean build. Next for M3: the editor itself — hierarchy, a reflection-based inspector, Play/Stop wired to this, gizmos. All still ahead; this commit is only the kernel mechanic underneath Play/Stop. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N1qPfzq8TDCUMFMV3UwV5N
40 lines
1.7 KiB
C#
40 lines
1.7 KiB
C#
namespace Engine.Kernel.World;
|
|
|
|
/// <summary>
|
|
/// Kernel-owned storage for every <see cref="GameObject"/> in a scene.
|
|
/// Shape sketched from its usage throughout docs/kernel-contract.md — not a
|
|
/// final API; M0's job is to actually implement this.
|
|
/// </summary>
|
|
public interface IWorld
|
|
{
|
|
/// <summary>Top-level GameObjects — everything with no parent.</summary>
|
|
IReadOnlyList<GameObject> Roots { get; }
|
|
|
|
GameObject CreateGameObject(string name);
|
|
|
|
void Destroy(GameObject go);
|
|
|
|
/// <summary>Type-indexed lookup — O(matches), not O(all). See §2.</summary>
|
|
IEnumerable<GameObject> Query<T>() where T : Component;
|
|
|
|
/// <summary>
|
|
/// A deep, opaque snapshot of every GameObject and Component — for
|
|
/// Play mode (§5): taken on EnterPlay, handed back to
|
|
/// <see cref="Restore"/> on ExitPlay to discard whatever changed while
|
|
/// playing. Backed by <see cref="SceneFormat"/> rather than a
|
|
/// separate clone mechanism — a scene file and a Play-mode snapshot
|
|
/// are the same problem (capture every GameObject's state, faithfully
|
|
/// enough to reconstruct it) at two different moments, and reusing
|
|
/// already-proven serialization is cheaper than maintaining a second
|
|
/// way to walk the same graph.
|
|
/// </summary>
|
|
string Snapshot();
|
|
|
|
/// <summary>Destroys every current root and rebuilds the graph
|
|
/// <paramref name="snapshot"/> describes. Not merged with what's
|
|
/// there — Play mode always restores onto a world it's about to fully
|
|
/// own, so additive Load() semantics would be the wrong default here,
|
|
/// unlike SceneFormat.Load's own.</summary>
|
|
void Restore(string snapshot);
|
|
}
|