-
-
Notifications
You must be signed in to change notification settings - Fork 0
DIAGNOSTIC_ADAPTERS
Diagnostics in Gravitas are data streams, not renderer calls. Core runtime code
emits deterministic GravitasDiagnosticEvent values and
GravitasDebugDrawCommand values into context.Diagnostics; host adapters
translate those streams into engine-specific overlays, logs, captures, or replay
tools outside src/Gravitas.
Read Diagnostics for the event and draw command reference.
- Keep adapter code in host, sample, or tooling projects.
- Consume diagnostics after the deterministic frame or capture window.
- Preserve
FrameandSequenceas ordering keys. - Resolve context-local IDs only against the producing context.
- Translate fixed-point values at the host boundary.
- Do not feed diagnostics back into authoritative simulation decisions.
An adapter should:
- consume diagnostics after the deterministic frame or debug capture window has finished.
- preserve
FrameandSequenceas ordering keys. - resolve body, collider, and joint IDs through the same
GravitasWorldContextthat produced the payload. - translate fixed-point values at the edge when the host renderer or log format requires floats or text.
- call
context.Diagnostics.Clear()after consumption when the host wants a per-frame stream.
An adapter should not:
- mutate
SolidBody,SolidBody2D, collider, partition, query, or constraint state while consuming diagnostics. - make authoritative simulation decisions from diagnostic payloads.
- assume collider IDs are global, stable across contexts, or valid after reset.
- add engine-specific renderer, file-system, networking, or editor dependencies to the Gravitas core library.
Renderer adapters usually need a small command sink that mirrors the host's debug drawing API. The adapter owns conversion to host units, colors, and duration.
public interface IHostDebugDrawSink
{
void DrawLine(Vector3d start, Vector3d end, GravitasDiagnosticColor color);
void DrawPoint(Vector3d center, Fixed64 radius, GravitasDiagnosticColor color);
void DrawWireSphere(Vector3d center, Fixed64 radius, GravitasDiagnosticColor color);
void DrawWireBox(Vector3d center, Vector3d halfExtents, FixedQuaternion rotation, GravitasDiagnosticColor color);
void DrawWireCylinder(Vector3d center, Fixed64 radius, Fixed64 height, FixedQuaternion rotation, GravitasDiagnosticColor color);
void DrawWireCone(Vector3d center, Fixed64 radius, Fixed64 height, FixedQuaternion rotation, GravitasDiagnosticColor color);
void DrawWireCapsule(Vector3d center, Fixed64 radius, Fixed64 axisLength, FixedQuaternion rotation, GravitasDiagnosticColor color);
void DrawWireTriangle(Vector3d a, Vector3d b, Vector3d c, GravitasDiagnosticColor color);
}public sealed class HostDebugDrawAdapter : GravitasDebugDrawCommandVisitor
{
private readonly IHostDebugDrawSink _sink;
public HostDebugDrawAdapter(IHostDebugDrawSink sink)
{
_sink = sink;
}
public override void VisitLine(in GravitasLineDebugDrawView view) =>
_sink.DrawLine(view.Start, view.End, view.Color);
public override void VisitRay(in GravitasRayDebugDrawView view) =>
_sink.DrawLine(view.Start, view.End, view.Color);
public override void VisitPoint(in GravitasPointDebugDrawView view) =>
_sink.DrawPoint(view.Center, view.Radius, view.Color);
public override void VisitWireSphere(in GravitasWireSphereDebugDrawView view) =>
_sink.DrawWireSphere(view.Center, view.Radius, view.Color);
public override void VisitWireBox(in GravitasWireBoxDebugDrawView view) =>
_sink.DrawWireBox(view.Center, view.HalfExtents, view.Rotation, view.Color);
public override void VisitWireCylinder(in GravitasWireCylinderDebugDrawView view) =>
_sink.DrawWireCylinder(
view.Center,
view.Radius,
view.Height,
view.Rotation,
view.Color);
public override void VisitWireCone(in GravitasWireConeDebugDrawView view) =>
_sink.DrawWireCone(
view.Center,
view.Radius,
view.Height,
view.Rotation,
view.Color);
public override void VisitWireCapsule(in GravitasWireCapsuleDebugDrawView view) =>
_sink.DrawWireCapsule(
view.Center,
view.Radius,
view.AxisLength,
view.Rotation,
view.Color);
public override void VisitWireTriangle(in GravitasWireTriangleDebugDrawView view) =>
_sink.DrawWireTriangle(view.PointA, view.PointB, view.PointC, view.Color);
}
public static void FlushDebugDraw(
GravitasWorldContext context,
HostDebugDrawAdapter adapter) =>
context.Diagnostics.DispatchDrawCommandsTo(adapter);2D debug draw in mixed mode is emitted as finite 3D slab geometry. Use
ColliderDimension and Collider2DType to style embedded 2D geometry
separately from normal 3D colliders.
Mesh and compound capture can emit many commands. Reserve draw-command capacity before a capture-heavy run and avoid full mesh capture every frame in normal gameplay.
Server or headless hosts can ignore draw commands and write diagnostic events to
a deterministic log sink. Prefer GravitasDiagnosticEventVisitor so decoding
stays centralized in Gravitas.
public interface IHostDiagnosticLogSink
{
void Write(
int frame,
int sequence,
GravitasDiagnosticEventKind kind,
string payload);
}public sealed class HostDiagnosticLogAdapter : GravitasDiagnosticEventVisitor
{
private readonly IHostDiagnosticLogSink _sink;
public HostDiagnosticLogAdapter(IHostDiagnosticLogSink sink)
{
_sink = sink;
}
public override void VisitForceDelta(in GravitasForceDeltaDiagnosticView view) =>
_sink.Write(
view.Frame,
view.Sequence,
view.Event.Kind,
$"body={view.BodyId} force={view.Force} accelDelta={view.AccelerationDelta}");
public override void VisitRayQuery(in GravitasRayQueryDiagnosticView view) =>
_sink.Write(
view.Frame,
view.Sequence,
view.Event.Kind,
$"hit={view.Hit} collider={view.HitColliderId} distance={view.Distance}");
public override void VisitContact(in GravitasContactDiagnosticView view) =>
_sink.Write(
view.Frame,
view.Sequence,
view.Event.Kind,
$"a={view.ColliderAId} b={view.ColliderBId} depth={view.Depth}");
public override void VisitMixedContact(in GravitasMixedContactDiagnosticView view) =>
_sink.Write(
view.Frame,
view.Sequence,
view.Event.Kind,
$"3d={view.Collider3DId} 2d={view.Collider2DId} depth={view.Depth}");
}
public static void FlushEvents(
GravitasWorldContext context,
HostDiagnosticLogAdapter adapter) =>
context.Diagnostics.DispatchEventsTo(adapter);For production logs, prefer a structured payload object over ad hoc strings. The
important rule is that adapters consume semantic typed views instead of decoding
ScalarA, ScalarB, DataA, and DataB directly.
Replay tooling should keep diagnostics beside the authoritative replay frame, not inside the authoritative snapshot. A simple frame capture can store events and draw commands in order:
public readonly struct DiagnosticFrameCapture
{
public DiagnosticFrameCapture(
int frame,
GravitasDiagnosticEvent[] events,
GravitasDebugDrawCommand[] drawCommands)
{
Frame = frame;
Events = events;
DrawCommands = drawCommands;
}
public int Frame { get; }
public GravitasDiagnosticEvent[] Events { get; }
public GravitasDebugDrawCommand[] DrawCommands { get; }
}public static DiagnosticFrameCapture CaptureTimelineFrame(
GravitasWorldContext context)
{
ReadOnlySpan<GravitasDiagnosticEvent> events =
context.Diagnostics.Events;
ReadOnlySpan<GravitasDebugDrawCommand> drawCommands =
context.Diagnostics.DrawCommands;
return new DiagnosticFrameCapture(
context.FrameCount,
events.ToArray(),
drawCommands.ToArray());
}The array allocation belongs to the tooling edge. Long-running replay tools should pool or stream capture storage when diagnostics are enabled for many frames.
The event struct intentionally uses generic numeric fields:
-
ScalarAandScalarBfor fixed-point payload values. -
DataAandDataBfor integer payload values.
The generic payload table in Diagnostics is the storage
contract. GravitasDiagnosticEventVisitor and typed event views are the
preferred adapter-facing decode surface. Lower-level TryAs... helpers are
useful for one-off filters over known event kinds, not for full adapter
dispatch.
Draw commands follow the same pattern: GravitasDebugDrawCommand stays compact,
while GravitasDebugDrawCommandVisitor exposes typed draw views for renderer
adapters. Do not overload an event or draw kind with undocumented meanings.
| Area | Source |
|---|---|
| Event visitors/views | src/Gravitas/Diagnostics/Events |
| Draw visitors/views | src/Gravitas/Diagnostics/DebugDraw |
| Diagnostic sink | src/Gravitas/Diagnostics/GravitasDiagnosticSink.cs |