# Migrating From v0.3 to v0.4

## Bevy 0.17

PRs: [#815](https://github.com/avianphysics/avian/pull/815)

**Avian 0.4** migrates Avian to [Bevy 0.17](https://bevy.org/news/bevy-0-17/). This involves some breaking changes.

### Collision Events

The `CollisionStarted`, `CollisionEnded`, `OnCollisionStart`, and `OnCollisionEnd` events have been replaced by the `CollisionStart` and `CollisionEnd` events. They are both written as a `Message` and triggered as an `Event`, and store the collider and body entity of both colliders involved in the event.

A collision event observer before:

```rust
fn on_player_stepped_on_plate(event: Trigger<OnCollisionStart>, player_query: Query<&Player>) {
    let pressure_plate = event.target();
    let other_entity = event.collider;

    if player_query.contains(other_entity) {
        println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
    }
}
```

and after:

```rust
fn on_player_stepped_on_plate(event: On<CollisionStart>, player_query: Query<&Player>) {
    let pressure_plate = event.collider1;
    let other_entity = event.collider2;

    if player_query.contains(other_entity) {
        println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
    }
}
```

A collision event reader system before:

```rust
fn print_started_collisions(mut collision_reader: EventReader<CollisionStarted>) {
    for CollisionStarted(collider1, collider2) in collision_reader.read() {
        println!("{collider1} and {collider2} started colliding");
    }
}
```

and after:

```rust
fn print_started_collisions(mut collision_reader: MessageReader<CollisionStart>) {
    // Note: The event now also stores `body1` and `body2`
    for event in collision_reader.read() {
        println!("{} and {} started colliding", event.collider1, event.collider2);
    }
}
```

### System Sets

System sets have been renamed to follow the new `FooSystems` naming convention.

- `PhysicsSet` → `PhysicsSystems`
- `PhysicsStepSet` → `PhysicsStepSystems`
- `SubstepSet` → `SubstepSystems`
- `SubstepSolverSet` → `SubstepSolverSystems`
- `SolverSet` → `SolverSystems`
- `IntegrationSet` → `IntegrationSystems`
- `BroadPhaseSet` → `BroadPhaseSystems`
- `NarrowPhaseSet` → `NarrowPhaseSystems`
- `SweptCcdSet` → `SweptCcdSystems`
- `PhysicsTransformSet` → `PhysicsTransformSystems`

### `ColliderConstructorHierarchy`

Bevy 0.17 changed the way `Name` works for glTF mesh primitives ([migration guide](https://bevy.org/learn/migration-guides/0-16-to-0-17/#use-gltf-material-names-for-spawned-primitive-entities)). Instead of `MeshName.PrimitiveIndex`, it is now in the form of `MeshName.MaterialName`. This also means that APIs such as `ColliderConstructorHierarchy::with_constructor_for_name` now use this format.

```rust
ColliderConstructorHierarchy::new(ColliderConstructor::ConvexDecompositionFromMesh)
    .with_density_for_name("armL_mesh.ferris_material", 3.0)
    .with_density_for_name("armR_mesh.ferris_material", 3.0)
```

## Force Overhaul

PRs: [#770](https://github.com/avianphysics/avian/pull/770)

**Avian 0.4** overhauls the force APIs, and removes the `ExternalForce`, `ExternalTorque`, `ExternalImpulse`, and `ExternalAngularImpulse` components.

- For persistent forces and torques, use the new `ConstantForce` and `ConstantTorque` components.
- For non-persistent forces that get cleared automatically, use the new `Forces` helper `QueryData`.
- Impulses can no longer be persistent. Use persistent forces instead.

The new `ForcePlugin` must be enabled for forces to function properly. It is included in `PhysicsPlugins` by default.

## Joints

PRs: [#517](https://github.com/avianphysics/avian/pull/517), [#735](https://github.com/avianphysics/avian/pull/735), [#799](https://github.com/avianphysics/avian/pull/799), [#803](https://github.com/avianphysics/avian/pull/803)

**Avian 0.4** contains a _lot_ of changes and improvements for joints.

### Core APIs

- Joint APIs are now in `dynamics::joints` instead of `dynamics::solver::joints`
- The `Joint` trait has been removed in favor of the `EntityConstraint` trait and helper methods on the joint types themselves
- Renamed `entity1` and `entity2` to `body1` and `body2`
- Renamed `free_axis` to `slider_axis` for `PrismaticJoint`
- Renamed `aligned_axis` to `hinge_axis` for `RevoluteJoint`
- Renamed `with_local_anchor_1`, `with_local_anchor_2`, `local_anchor_1`, and `local_anchor_2` to `with_local_anchor1`, `with_local_anchor2`, `local_anchor1`, and `local_anchor2`
- The `local_anchor1` and `local_anchor2` methods now return an `Option`
- The `FixedJoint`, `PrismaticJoint`, `RevoluteJoint`, and `SphericalJoint` now store a full `JointFrame` (anchor + basis) for each body instead of just local anchors
- Removed `swing_axis` from `SphericalJoint`; just set the `twist_axis`, and the swing limit cone will be oriented accordingly
- Removed damping properties and methods from joint types in favor of the `JointDamping` component
- Removed force properties and methods from joint types in favor of the `JointForces` component
- Each part of a joint has its own compliance and helpers for it, such as `with_point_compliance` and `with_swing_compliance`.

### Only One Joint Per Entity

Entities can now only hold up to one type of joint component. If a joint is added on an entity that already has a joint, the old joint is automatically removed, and a warning is emitted if `debug_assertions` are enabled. A rigid body can still be attached to other bodies by multiple joints, but each joint must be on its own entity.

`ContactEdge` now also stores the rigid body entities.

### Remove `DistanceJoint::rest_length`

The `rest_length` property of `DistanceJoint` has been removed in favor of just using `length_limits`.

- Replace `DistanceJoint::with_rest_length(1.0)` with `DistanceJoint::with_limits(1.0, 1.0)`.
- Replace `joint.rest_length = 1.0` with `joint.length_limits = 1.0.into()`.

### Solver Reorganization and XPBD

- XPBD logic is now contained within `dynamics::solver::xpbd`, gated behind the `xpbd_joints` feature
- XPBD system sets from `SubstepSolverSet` have been extracted to a separate `XpbdSolverSystems` enum
- XPBD systems are now initialized by an `XpbdSolverPlugin`

### Custom XPBD Constraints

- The `XpbdConstraint` trait now has a `prepare` step to prepare base translational and rotational offsets and any other pre-step data.
- `XpbdConstraint` now has a `SolverData` associated type for a solver data component implementing the `XpbdConstraintSolverData` trait. This is taken by `prepare` and `solve`.
- `XpbdConstraint::solve` and many related methods now use `SolverBody` and `SolverBodyInertia` structs. Positional corrections are applied to the `delta_position` and `delta_rotation` properties. Updated positional information can be computed based on the pre-step data and these deltas.
- `apply_positional_lagrange_update` has been removed. Use `apply_positional_impulse` instead.
- `xpbd::solve_constraint` is now `xpbd::solve_xpbd_joint`, and only supports two entities (make your own system if you need more).
- Most methods that previously returned forces or torques now return Lagrange multiplier updates.
- See the `custom_constraint` example for a functional demonstration of implementing a custom constraint.

## Contact APIs

PRs: [#771](https://github.com/avianphysics/avian/pull/771), [#788](https://github.com/avianphysics/avian/pull/788)

### Contact Impulses

`ContactPoint::normal_impulse` previously corresponded to the clamped accumulated normal impulse from the last substep, used for warm starting the contact solver. It did _not_ represent the total impulse applied across substeps and restitution, despite the ambiguous name.

Now, `ContactPoint::normal_impulse` works like you would expect, and represents the total normal impulse applied at a contact point. Divide by the time step to get the corresponding force.

The old warm starting impulses are now stored as `warm_start_normal_impulse` and `warm_start_tangent_impulse` (previously `tangent_impulse`).

The method APIs such as `total_normal_impulse`, `total_normal_impulse_magnitude`, and `max_normal_impulse` have been updated accordingly to use the new `normal_impulse`. Additionally, `ContactPair::max_normal_impulse` has been split into `ContactPair::max_normal_impulse` (returns a vector) and `ContactPair::max_normal_impulse_magnitude` (returns a scalar).

The `normal_force` and `tangent_force` methods of `ContactPoint` have been removed.

`ContactConstraintPoint::max_normal_impulse` is now stored in the `ContactNormalPart` as `total_impulse`.

### Contact Points

The `local_point1` and `local_point2` properties of `ContactPoint` have been removed in favor of a world-space `anchor1` and `anchor2` relative to the center of mass.

The `global_point1` and `global_point2` methods have also been removed, but a new world-space `point` is available for the midpoint between the closest points.

### Contact Graph

- The `ContactGraph` now stores `ContactEdge`s in the graph, containing only edge connectivity information with stable `ContactId`s.
- The `ContactGraph` now stores `ContactPair`s in separate `active_pairs` and `sleeping_pairs` lists.
- `iter` and `iter_mut` have been renamed to `iter_active` and `iter_active_mut` / `iter_sleeping` and `iter_sleeping_mut`.
- `iter_touching` and `iter_touching_mut` have been renamed to `iter_touching_active` and `iter_touching_active_mut` / `iter_touching_sleeping` and `iter_touching_sleeping_mut`.
- `collisions_with` has been renamed to `contact_pairs_with`.
- `collisions_with_mut` has been removed for now.
- `add_pair` has been replaced by `add_edge`, and `add_pair_with_key` has been replaced by `add_edge_and_key_with`.
- `insert_pair` and `insert_pair_with` have been removed. Add or update pairs manually instead.
- `remove_pair` has been renamed to `remove_edge`.

### Contact Pairs

- `ContactPair` now stores the `ContactId` associated with the `ContactEdge` in the `ContactGraph`. It must be provided to `ContactPair::new`. It is initialized automatically by calls to methods like `ContactGraph::add_edge`.
- `ContactPairFlags` no longer stores whether `CONTACT_EVENTS` are enabled. It is instead stored on `ContactEdgeFlags`.
- `ContactManifold` no longer stores the `index` of the manifold.

## Sleeping and Simulation Islands

PRs: [#809](https://github.com/avianphysics/avian/pull/809)

Stacks of bodies as well as bodies connected by joints now form "simulation islands" that are allowed to enter a low-cost sleeping state when all bodies in a given island are resting. This can significantly reduce CPU overhead for large game worlds with lots of dynamic bodies. Previously, bodies were only allowed to sleep when they were not interacting with other dynamic bodies.

The following components have been renamed:

- `TimeSleeping` -> `SleepTimer`
- `SleepingThreshold` -> `SleepThreshold`
- `DeactivationTime` -> `TimeToSleep` (also a component and not a resource now)

Additionally, the `SleepingPlugin` has been replaced by the `IslandSleepingPlugin`.

## Solver Bodies

PRs: [#735](https://github.com/avianphysics/avian/pull/735)

Avian's solver now uses special `SolverBody` and `SolverBodyInertia` components instead of separate components like `Position`, `Rotation`, `AccumulatedTranslation`, `LinearVelocity`, and `AngularVelocity`. They are initialized for awake dynamic and kinematic bodies in the substepping loop, and the results are written back to the user-facing components at the end. This also means that if you are running custom logic inside the substepping loop, you should generally use `SolverBody` instead of the separate components.

Solver bodies were added to drastically improve the performance of the solver, but it also means significant changes to internals.

### Removed Components and Properties

The following components have been removed and are no longer stored for rigid bodies:

- `AccumulatedTranslation`
- `PreSolveAccumulatedTranslation` (now called `PreSolveDeltaPosition`)
- `PreSolveLinearVelocity`
- `PreSolveAngularVelocity`
- `PreSolveRotation`
- `PreviousRotation`

A new `PreSolveDeltaRotation` component has also been added.

The `current_position` helper on `RigidBodyQueryItem` and `ColliderQueryItem` has been removed.

The `local_anchor1` and `local_anchor2` properties on `ContactConstraintPoint` have been removed.

### Other

- `SolverSet::ApplyTranslation` has been renamed to `SolverSystems::Finalize`.

## Physics Transforms and `PreparePlugin`

PRs: [#760](https://github.com/avianphysics/avian/pull/760), [#785](https://github.com/avianphysics/avian/pull/785)

- `Position`, `Rotation`, and `ColliderAabb` are now initialized with correct world-space values right after spawn.
- The `SyncPlugin` has been renamed to `PhysicsTransformPlugin`, and `SyncSet` has been renamed to `PhysicsTransformSystems`.
- The `PreparePlugin` and `PrepareSet` have been removed. Use `PhysicsSet::Prepare` for preparation logic, and run it after `PhysicsTransformSystems::TransformToPosition` if it must run after transforms have been applied to physics positions.
- Logic inside the `PhysicsSchedule` can no longer use `Transform`. Use `Position` and `Rotation` instead.
- `PhysicsSet::Sync` has been renamed to `PhysicsSet::Writeback`.
- `SyncConfig` has been renamed to `PhysicsTransformConfig`.

## Symmetric 3x3 RMatrix for Angular Inertia

PRs: [#777](https://github.com/avianphysics/avian/pull/777)

In 3D, `AngularInertia` and `ComputedAngularInertia` APIs now use a `SymmetricMat3` from [`glam_natrix_extras`](https://github.com/Jondolf/glam_matrix_extras) instead of the old `Mat3` for the angular inertia tensor. `AngularInertia` has new constructors like `try_from_mat3` and `from_mat3_unchecked` to use `Mat3` directly.

The `GlobalAngularInertia` component has been removed. You can compute the rotated angular inertia tensor using `ComputedAngularInertia::rotated`.

## Debug Rendering

PRs: [#829](https://github.com/avianphysics/avian/pull/829)

The `PhysicsDebugPlugin` now always runs in `PostUpdate`. Replace calls to `PhysicsDebugPlugin::new(SomeSchedule)` with `PhysicsDebugPlugin` or `PhysicsDebugPlugin::default()`.

Additionally, debug rendering now uses `GlobalTransform` instead of `Position` and `Rotation`. This allows debug rendering to use interpolated transforms if `TransformInterpolation` is used.

## Fallible Trimesh Colliders

PRs: [#761](https://github.com/avianphysics/avian/pull/761)

`Collider::trimesh` and `Collider::trimesh_with_config` can now panic for degenerate input. Use `Collider::try_trimesh` and `Collider::try_trimesh_with_config` to instead get a `Result` and handle error cases manually.

## Remove `ColliderQuery`

PRs: [#775](https://github.com/avianphysics/avian/pull/775)

The `ColliderQuery` `QueryData` type no longer exists. Query for the components you need manually, or define your own `QueryData` type.
