Files
EmilandClaude Sonnet 5 d7fcc20f5e M3: Play/Stop — Engine.Host stops ticking Stage.Update outside Play mode
IPlayModeController (Engine.Editor.Contracts) wraps IWorld.Snapshot()/
Restore() as EnterPlay/ExitPlay — the entire mechanism is that one
snapshot, per Snapshot's own doc comment. Exposed as a service, not just
something engine.editor's UI calls directly, so a future non-UI driver
(a test harness, a headless "play for N frames" CLI command) can drive
Play mode without depending on ImGui.

Engine.Host now looks up IPlayModeController once and checks IsPlaying
every frame before running Stage.Update: Edit mode still renders the
scene (so the view isn't frozen and the editor UI stays responsive) but
never ticks it, same distinction Unity draws between its Scene and Game
views. A project with no engine.editor loaded sees no behavior change —
Update runs unconditionally, same as before this existed.

Added "play"/"stop" as stdin commands alongside the existing "r" and
"screenshot", both real controls (not just test scaffolding) for driving
Play mode without a mouse — which is also how this got verified: an
interactive run sent "play", screenshotted, sent "stop", and the log
shows "Entered Play mode in 13.2ms", the real editor path exercising the
same under-100ms budget WorldSnapshotTests already proves at the kernel
level. The Lingua Editor panel's button/label flip Play/(Edit mode) to
Stop/(Playing) correctly across both screenshots.

Also fixes a real layout bug hit while verifying this: SetNextWindowPos
with ImGuiCond.FirstUseEver only applies with no prior imgui.ini entry
for that window title, and this project had already accumulated one from
earlier runs (all three panels stacked exactly on top of each other) —
gave each panel its own default position and .gitignore'd imgui.ini,
which is per-machine session state, not source.

Full suite still green: 65 tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1qPfzq8TDCUMFMV3UwV5N
2026-09-02 16:26:23 +03:00

46 lines
1.4 KiB
C#

using System.Diagnostics;
using Engine.Editor.Contracts;
using Engine.Kernel.Diagnostics;
using Engine.Kernel.World;
namespace Engine.Editor;
/// <summary>
/// A snapshot taken on EnterPlay is the only state this needs — see
/// IWorld.Snapshot's doc comment for why that's Play mode's entire
/// mechanism, not a simplification of some richer one. Logs EnterPlay's
/// wall-clock cost: M3's "done when" criterion is entering Play in under
/// 100ms, already proven at the kernel level by WorldSnapshotTests'
/// 300-GameObject timing assertion — this is the same measurement taken
/// through the real editor path instead of a unit test, so a regression
/// specific to this plugin (not the kernel primitive) would show up here
/// even if the kernel test stays green.
/// </summary>
internal sealed class PlayModeController(IWorld world, ILogger log) : IPlayModeController
{
private string? _snapshot;
public bool IsPlaying => _snapshot is not null;
public void EnterPlay()
{
if (IsPlaying)
return;
var stopwatch = Stopwatch.StartNew();
_snapshot = world.Snapshot();
stopwatch.Stop();
log.Info($"Entered Play mode in {stopwatch.Elapsed.TotalMilliseconds:F1}ms");
}
public void ExitPlay()
{
if (!IsPlaying)
return;
world.Restore(_snapshot!);
_snapshot = null;
log.Info("Exited Play mode");
}
}