SimulationDataComponent
A singleton component updated every frame that tracks how many bodies participate in the current pipeline step and chains Unity Job System work across import, the fixed-step loop, and export.
Any custom job that reads or writes native physics buffers must respect both fields.
Component fields
| Field | Type | Description |
|---|---|---|
ActiveBodiesCount | int | Number of bodies imported for the current step (valid indices: 0 … ActiveBodiesCount - 1) |
PhysicsJobHandle | JobHandle | Combined dependency for all scheduled physics jobs so far this frame |
ActiveBodiesCount
Set each LateSimulation import by ImportPhysicsDataSystem:
simulation.ActiveBodiesCount = math.min(CountQuery.CalculateEntityCount(), maxEntitiesCount);
CountQuery includes entities with LocalToWorld, PhysicsBodyComponent, and PhysicsBodyUpdateComponent. The count is clamped to PhysicsFixedSettingsComponent.BlobRef.Value.MaxEntitiesCount — bodies beyond the cap are not copied into native memory.
What uses the count
Parallel jobs and native arrays are indexed by ActiveBodiesCount, not the allocated pool size:
| Structure | Relationship |
|---|---|
BodiesList | Indices 0 … ActiveBodiesCount - 1 hold live body data |
Randoms | One RNG stream per active body index |
SurfaceCollisionMap | One surface contact slot per body index |
CollisionDataMap | Outer array length matches active bodies |
Internal systems (GravitySystem, FrictionSystem, CollisionDetectionSystem, and others) pass ActiveBodiesCount as the loop length when scheduling parallel jobs.
Custom IBodiesJob, ICollisionJob, ISurfaceJob, and ILineCastJob extensions also schedule over ActiveBodiesCount.
PhysicsJobHandle
Every internal physics system and package job extension combines with PhysicsJobHandle before scheduling, then writes the new handle back:
ref var simulation = ref SystemAPI.GetSingletonRW<SimulationDataComponent>().ValueRW;
var combined = JobHandle.CombineDependencies(state.Dependency, simulation.PhysicsJobHandle);
var handle = myJob.Schedule(combined);
simulation.PhysicsJobHandle = handle;
state.Dependency = handle;
This serializes access to shared native arrays (BodiesList, maps, collision buffers) across:
- Import —
ImportPhysicsDataSystemfills bodies and entity map - Fixed step — gravity through surface collision, then user jobs, then velocity integration
- Export — writes native results back to ECS components
If you schedule a job that touches physics native memory without combining and updating
PhysicsJobHandle, it may run concurrently with other physics jobs and corrupt buffers.
When interfaces handle chaining for you
Inside LittlePhysicsUserSystemGroup, prefer the package job interfaces. Their ScheduleAndChain extension methods combine dependencies and update PhysicsJobHandle automatically:
myBodiesJob.ScheduleAndChain(ref state, structures, ref simulation);
See IBodiesJob for ScheduleAndChain on package interfaces, Custom job interfaces for raw IJobParallelFor chaining, and Import workflow for group placement.
Read-only access
Gameplay or UI code that only needs the live body count can read the singleton without chaining jobs:
int count = SystemAPI.GetSingleton<SimulationDataComponent>().ActiveBodiesCount;
The sample PerformanceOutputPresenter uses this pattern to display active body statistics.
Related
- PhysicsReadyTag — gate systems until bootstrap finishes
- BodiesList — native body pool filled during import
- Custom job interfaces — raw
IJobParallelForandPhysicsJobHandle - Pipeline — Chaining jobs with PhysicsJobHandle
- How it works — Import