using OECS; using R3; namespace OECS.PlayTest; /// /// Captures all entity changes from the World's observable API and produces /// a compact text log on demand. Call to enrich /// component entries with human-readable values. /// public sealed class ObservableCapture : IDisposable { private readonly World _world; private readonly IDisposable _subscription; private readonly List _events = new(); private readonly Dictionary> _formatters = new(); public ObservableCapture(World world) { _world = world; _subscription = world.ObserveEntityChanges().Subscribe(OnChange); } /// /// Registers a formatter for component type . /// When a change for this type is captured, the formatted value is /// included in the log output. /// public void FormatWith(Func formatter) where T : struct { _formatters[typeof(T)] = (w, e) => { var value = w.ReadComponent(e); return formatter(value); }; } /// /// Returns the captured log as a single string with one line per change. /// public string GetLog() => string.Join(Environment.NewLine, GetLogLines()); /// /// Returns the captured log as a list of lines, one per change. /// public List GetLogLines() { var lines = new List(_events.Count); foreach (var evt in _events) { var change = evt.Change; var kind = change.Kind.ToString(); if (change.ComponentType != null) { var typeName = change.ComponentType.Name; if (evt.FormattedValue != null) lines.Add($"{kind} {typeName} = {evt.FormattedValue} on {change.Entity}"); else lines.Add($"{kind} {typeName} on {change.Entity}"); } else { lines.Add($"{kind} on {change.Entity}"); } } return lines; } public void Dispose() => _subscription.Dispose(); private void OnChange(EntityChange change) { string? formattedValue = null; if (change.ComponentType != null && change.Kind != ChangeKind.ComponentRemoved && change.Kind != ChangeKind.EntityRemoved && change.Kind != ChangeKind.RelationshipReordered && _formatters.TryGetValue(change.ComponentType, out var formatter)) { formattedValue = formatter(_world, change.Entity); } _events.Add(new CapturedEvent(change, formattedValue)); } private readonly struct CapturedEvent { public readonly EntityChange Change; public readonly string? FormattedValue; public CapturedEvent(EntityChange change, string? formattedValue) { Change = change; FormattedValue = formattedValue; } } }