// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Real 3D kinematic character controller (3DReal backend).
///
/// This is a direct analogue of the 2D `KinematicCharacterController` for the 3DReal backend query
/// types (`QueryPipeline3DReal` / `Shape3D` / `ShapeCastHit3`).

///|
pub struct EffectiveMovement3DReal {
  translation : @core.Vec3
  grounded : Bool
  is_sliding_down_slope : Bool
}

///|
pub fn EffectiveMovement3DReal::translation(
  self : EffectiveMovement3DReal,
) -> @core.Vec3 {
  self.translation
}

///|
pub fn EffectiveMovement3DReal::is_grounded(
  self : EffectiveMovement3DReal,
) -> Bool {
  self.grounded
}

///|
pub fn EffectiveMovement3DReal::is_sliding_down_slope(
  self : EffectiveMovement3DReal,
) -> Bool {
  self.is_sliding_down_slope
}

///|
pub struct CharacterCollision3DReal {
  handle : @collision.ColliderHandle3D
  hit : @collision.ShapeCastHit3
  translation_applied : @core.Vec3
  translation_remaining : @core.Vec3
  character_pos : @core.Isometry3
}

///|
pub fn CharacterCollision3DReal::handle(
  self : CharacterCollision3DReal,
) -> @collision.ColliderHandle3D {
  self.handle
}

///|
pub fn CharacterCollision3DReal::hit(
  self : CharacterCollision3DReal,
) -> @collision.ShapeCastHit3 {
  self.hit
}

///|
pub fn CharacterCollision3DReal::translation_applied(
  self : CharacterCollision3DReal,
) -> @core.Vec3 {
  self.translation_applied
}

///|
pub fn CharacterCollision3DReal::translation_remaining(
  self : CharacterCollision3DReal,
) -> @core.Vec3 {
  self.translation_remaining
}

///|
pub fn CharacterCollision3DReal::character_pos(
  self : CharacterCollision3DReal,
) -> @core.Isometry3 {
  self.character_pos
}

///|
pub struct KinematicCharacterController3DReal {
  up : @core.Vec3
  offset : CharacterLength
  slide : Bool
  autostep : CharacterAutostep?
  max_slope_climb_angle : @core.Real
  min_slope_slide_angle : @core.Real
  snap_to_ground : CharacterLength?
  normal_nudge_factor : @core.Real
}

///|
pub fn KinematicCharacterController3DReal::KinematicCharacterController3DReal() -> KinematicCharacterController3DReal {
  {
    up: Vec3(0.0F, 1.0F, 0.0F),
    offset: CharacterLength::relative(0.01F),
    slide: true,
    autostep: None,
    max_slope_climb_angle: @core.pi() * 0.25F,
    min_slope_slide_angle: @core.pi() * 0.25F,
    snap_to_ground: Some(CharacterLength::relative(0.2F)),
    normal_nudge_factor: 1.0e-4F,
  }
}

///|
pub fn KinematicCharacterController3DReal::default() -> KinematicCharacterController3DReal {
  KinematicCharacterController3DReal()
}

///|
pub fn KinematicCharacterController3DReal::with_up(
  self : KinematicCharacterController3DReal,
  up : @core.Vec3,
) -> KinematicCharacterController3DReal {
  {
    up,
    offset: self.offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_offset(
  self : KinematicCharacterController3DReal,
  offset : CharacterLength,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_slide(
  self : KinematicCharacterController3DReal,
  slide : Bool,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_autostep(
  self : KinematicCharacterController3DReal,
  autostep : CharacterAutostep?,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide: self.slide,
    autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_max_slope_climb_angle(
  self : KinematicCharacterController3DReal,
  angle : @core.Real,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_min_slope_slide_angle(
  self : KinematicCharacterController3DReal,
  angle : @core.Real,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_snap_to_ground(
  self : KinematicCharacterController3DReal,
  snap : CharacterLength?,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: snap,
    normal_nudge_factor: self.normal_nudge_factor,
  }
}

///|
pub fn KinematicCharacterController3DReal::with_normal_nudge_factor(
  self : KinematicCharacterController3DReal,
  nudge : @core.Real,
) -> KinematicCharacterController3DReal {
  {
    up: self.up,
    offset: self.offset,
    slide: self.slide,
    autostep: self.autostep,
    max_slope_climb_angle: self.max_slope_climb_angle,
    min_slope_slide_angle: self.min_slope_slide_angle,
    snap_to_ground: self.snap_to_ground,
    normal_nudge_factor: nudge,
  }
}

///|
fn cc3d_real_character_length_eval(
  length : CharacterLength,
  reference : @core.Real,
) -> @core.Real {
  match length {
    Relative(value) => value * reference
    Absolute(value) => value
  }
}

///|
fn cc3d_real_min(a : @core.Real, b : @core.Real) -> @core.Real {
  if a < b {
    a
  } else {
    b
  }
}

///|
fn cc3d_real_max(a : @core.Real, b : @core.Real) -> @core.Real {
  if a > b {
    a
  } else {
    b
  }
}

///|
fn cc3d_real_try_normalize_and_get_length(
  v : @core.Vec3,
  eps : @core.Real,
) -> (@core.Vec3, @core.Real)? {
  let len2 = v.length_squared()
  if len2 <= eps * eps {
    None
  } else {
    let len = Float::sqrt(len2)
    Some((v.scale(1.0F / len), len))
  }
}

///|
fn cc3d_real_angle_between(u : @core.Vec3, v : @core.Vec3) -> @core.Real {
  // Robust 3D angle computation without acos: angle = atan2(|u×v|, u·v).
  let cross_len = u.cross(v).length()
  let dot = u.dot(v)
  @core.abs(@core.atan2(cross_len, dot))
}

///|
fn cc3d_real_split_into_components(
  up : @core.Vec3,
  translation : @core.Vec3,
) -> (@core.Vec3, @core.Vec3) {
  let vertical = up.scale(up.dot(translation))
  let horizontal = translation.sub(vertical)
  (vertical, horizontal)
}

///|
fn cc3d_real_subtract_hit(
  translation : @core.Vec3,
  hit : @collision.ShapeCastHit3,
) -> @core.Vec3 {
  let n = hit.normal()
  let surface_correction = cc3d_real_max(translation.scale(-1.0F).dot(n), 0.0F)
  // Match Rapier's small multiplier to avoid tunneling through walls.
  let surface_correction = surface_correction * (1.0F + 1.0e-5F)
  translation.add(n.scale(surface_correction))
}

///|
fn cc3d_real_compute_dims_with_up(
  shape : @collision.Shape3D,
  up : @core.Vec3,
) -> (@core.Real, @core.Real) {
  let aabb = shape.local_aabb()
  let extents = aabb.maxs.sub(aabb.mins).scale(0.5F)
  let up_abs = @core.Vec3(@core.abs(up.x), @core.abs(up.y), @core.abs(up.z))
  let up_extent = extents.dot(up_abs)
  let side_vec = extents.sub(up_abs.scale(up_extent))
  let side_extent = side_vec.length()
  (side_extent, up_extent)
}

///|
priv struct HitInfo3DReal {
  toi : @collision.ShapeCastHit3
  is_wall : Bool
  is_nonslip_slope : Bool
}

///|
priv struct HitDecomposition3DReal {
  normal_part : @core.Vec3
  horizontal_tangent : @core.Vec3
  vertical_tangent : @core.Vec3
}

///|
fn HitDecomposition3DReal::unconstrained_slide_part(
  self : HitDecomposition3DReal,
) -> @core.Vec3 {
  self.normal_part.add(self.horizontal_tangent).add(self.vertical_tangent)
}

///|
fn cc3d_real_compute_hit_info(
  controller : KinematicCharacterController3DReal,
  toi : @collision.ShapeCastHit3,
) -> HitInfo3DReal {
  let up = controller.up
  let angle_with_floor = cc3d_real_angle_between(up, toi.normal())
  let is_ceiling = up.dot(toi.normal()) < 0.0F
  let is_wall = angle_with_floor >= controller.max_slope_climb_angle &&
    !is_ceiling
  let is_nonslip_slope = angle_with_floor <= controller.min_slope_slide_angle
  { toi, is_wall, is_nonslip_slope, }
}

///|
fn cc3d_real_decompose_hit(
  controller : KinematicCharacterController3DReal,
  translation : @core.Vec3,
  hit : @collision.ShapeCastHit3,
) -> HitDecomposition3DReal {
  let n = hit.normal()
  let dist_to_surface = translation.dot(n)
  let (normal_part, penetration_part) = if dist_to_surface < 0.0F {
    (@core.Vec3::zero(), n.scale(dist_to_surface))
  } else {
    (n.scale(dist_to_surface), @core.Vec3::zero())
  }
  let tangent = translation.sub(normal_part).sub(penetration_part)
  let (vertical_tangent, horizontal_tangent) = cc3d_real_split_into_components(
    controller.up,
    tangent,
  )
  { normal_part, horizontal_tangent, vertical_tangent, }
}

///|
fn cc3d_real_handle_slopes(
  controller : KinematicCharacterController3DReal,
  hit : HitInfo3DReal,
  movement_input : @core.Vec3,
  translation_remaining : @core.Vec3,
) -> (@core.Vec3, Bool) {
  let up = controller.up
  let (vertical_input, horizontal_input) = cc3d_real_split_into_components(
    up, movement_input,
  )
  let horiz_input_decomp = cc3d_real_decompose_hit(
    controller,
    horizontal_input,
    hit.toi,
  )
  let decomp = cc3d_real_decompose_hit(
    controller,
    translation_remaining,
    hit.toi,
  )

  // An object is trying to slip if the tangential movement induced by its horizontal movement points downward.
  let slipping_intent = up.dot(horiz_input_decomp.vertical_tangent) < 0.0F
  // An object is slipping if its tangential movement points downward.
  let slipping = up.dot(decomp.vertical_tangent) < 0.0F

  // An object is trying to climb if its vertical input motion points upward.
  let climbing_intent = up.dot(vertical_input) > 0.0F
  // An object is climbing if the tangential movement induced by its movement points upward.
  let climbing = up.dot(decomp.vertical_tangent) > 0.0F
  let mut is_sliding = false
  let allowed = if hit.is_wall && climbing && !climbing_intent {
    decomp.horizontal_tangent.add(decomp.normal_part)
  } else if hit.is_nonslip_slope && slipping && !slipping_intent {
    decomp.horizontal_tangent.add(decomp.normal_part)
  } else {
    is_sliding = true
    decomp.unconstrained_slide_part()
  }
  let nudged = allowed.add(
    hit.toi.normal().scale(controller.normal_nudge_factor),
  )
  (nudged, is_sliding)
}

///|
fn cc3d_real_detect_ground_contact(
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  shape : @collision.Shape3D,
  position : @core.Isometry3,
  up : @core.Vec3,
  prediction : @core.Real,
  offset : @core.Real,
) -> (@collision.ColliderHandle3D, @core.Vec3, @core.Vec3)? {
  let down = up.scale(-1.0F)
  let options = @collision.ShapeCastOptions3(prediction, true).with_target_distance(
    offset,
  )
  if query.cast_shape(bodies, colliders, position, down, shape, options)
    is Some(hit) {
    let normal = hit.1.normal()
    // For the controller to be grounded, the angle between the contact normal and the up vector
    // has to be smaller than acos(1.0e-3) ≈ 89.94 degrees.
    if normal.dot(up) >= 1.0e-3F {
      Some((hit.0, normal, hit.1.point()))
    } else {
      None
    }
  } else {
    None
  }
}

///|
fn cc3d_real_detect_grounded(
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  shape : @collision.Shape3D,
  position : @core.Isometry3,
  up : @core.Vec3,
  prediction : @core.Real,
  offset : @core.Real,
) -> Bool {
  cc3d_real_detect_ground_contact(
    query, bodies, colliders, shape, position, up, prediction, offset,
  )
  is Some(_)
}

///|
fn cc3d_real_grounded_info(
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  shape : @collision.Shape3D,
  position : @core.Isometry3,
  up : @core.Vec3,
  prediction : @core.Real,
  offset : @core.Real,
) -> (Bool, @core.Vec3) {
  if cc3d_real_detect_ground_contact(
      query, bodies, colliders, shape, position, up, prediction, offset,
    )
    is Some(hit) {
    let handle = hit.0
    if query.collider(colliders, handle) is Some(co) &&
      co.parent is Some(parent) &&
      query.rigid_body(bodies, parent) is Some(body) &&
      body.body_type().is_kinematic() {
      (true, body.linvel())
    } else {
      (true, @core.Vec3::zero())
    }
  } else {
    (false, @core.Vec3::zero())
  }
}

///|
fn cc3d_real_attempt_autostep(
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  shape : @collision.Shape3D,
  start_pos : @core.Isometry3,
  remaining : @core.Vec3,
  controller : KinematicCharacterController3DReal,
  dims : (@core.Real, @core.Real),
  stair_handle : @collision.ColliderHandle3D,
  autostep : CharacterAutostep,
) -> (@core.Vec3, @core.Vec3)? {
  let up = controller.up
  let down = up.scale(-1.0F)
  let (side_extent, up_extent) = dims
  let offset = cc3d_real_character_length_eval(controller.offset, up_extent)
  let min_width = cc3d_real_character_length_eval(
      autostep.min_width(),
      side_extent,
    ) +
    offset
  let max_height = cc3d_real_character_length_eval(
      autostep.max_height(),
      up_extent,
    ) +
    offset
  if max_height <= 0.0F || min_width <= 0.0F {
    return None
  }
  if !autostep.include_dynamic_bodies() {
    // If the obstacle is dynamic, ignore it (Rapier parity).
    if query.collider(colliders, stair_handle) is Some(co) &&
      co.parent() is Some(parent) &&
      query.rigid_body(bodies, parent) is Some(body) &&
      body.body_type().is_dynamic() {
      return None
    }
  }
  let shifted_pos = @core.Isometry3(
    start_pos.translation.add(up.scale(max_height)),
    start_pos.rotation,
  )
  let horiz = remaining.sub(up.scale(up.dot(remaining)))
  let horizontal_dir = if cc3d_real_try_normalize_and_get_length(horiz, 1.0e-6F)
    is Some(step) {
    step.0
  } else {
    return None
  }

  // Can we go up?
  if query.cast_shape(
      bodies,
      colliders,
      start_pos,
      up,
      shape,
      @collision.ShapeCastOptions3(max_height, false).with_target_distance(
        offset,
      ),
    )
    is Some(_) {
    return None
  }

  // Is there enough room on the stair after stepping?
  if query.cast_shape(
      bodies,
      colliders,
      shifted_pos,
      horizontal_dir,
      shape,
      @collision.ShapeCastOptions3(min_width, false).with_target_distance(
        offset,
      ),
    )
    is Some(_) {
    return None
  }

  // Check the ramp we would land on isn't too steep.
  let pos_on_stair = @core.Isometry3(
    shifted_pos.translation.add(horizontal_dir.scale(min_width)),
    shifted_pos.rotation,
  )
  if query.cast_shape(
      bodies,
      colliders,
      pos_on_stair,
      down,
      shape,
      @collision.ShapeCastOptions3(max_height, false).with_target_distance(
        offset,
      ),
    )
    is Some(hit_down) {
    let (vertical_input, horizontal_input) = cc3d_real_split_into_components(
      up, remaining,
    )
    let vertical_slope = cc3d_real_subtract_hit(vertical_input, hit_down.1)
    let horizontal_slope = cc3d_real_subtract_hit(horizontal_input, hit_down.1)
    let slope_translation = horizontal_slope.add(vertical_slope)
    let angle = cc3d_real_angle_between(up, hit_down.1.normal())
    let climbing = up.dot(slope_translation) >= 0.0F
    if climbing && angle > controller.max_slope_climb_angle {
      return None
    }
  }

  // Find actual step height.
  let toi_down = if query.cast_shape(
      bodies,
      colliders,
      pos_on_stair,
      down,
      shape,
      @collision.ShapeCastOptions3(max_height, false).with_target_distance(
        offset,
      ),
    )
    is Some(hit2) {
    hit2.1.toi()
  } else {
    max_height
  }
  let step_height = max_height - toi_down
  let step = up.scale(step_height)
  let remaining1 = remaining.sub(step)
  let nudge_amt = cc3d_real_min(horizontal_dir.dot(remaining1), min_width)
  let horizontal_nudge = horizontal_dir.scale(nudge_amt)
  let remaining2 = remaining1.sub(horizontal_nudge)
  let delta = step.add(horizontal_nudge)
  Some((remaining2, delta))
}

///|
pub fn KinematicCharacterController3DReal::move_shape(
  self : KinematicCharacterController3DReal,
  dt : @core.Real,
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  shape : @collision.Shape3D,
  position : @core.Isometry3,
  translation : @core.Vec3,
  handle_collision : (CharacterCollision3DReal) -> Unit,
) -> EffectiveMovement3DReal {
  let up = if cc3d_real_try_normalize_and_get_length(self.up, 1.0e-6F)
    is Some(step) {
    step.0
  } else {
    Vec3(0.0F, 1.0F, 0.0F)
  }
  let controller = self.with_up(up)
  let (side_extent, up_extent) = cc3d_real_compute_dims_with_up(shape, up)
  let offset = cc3d_real_character_length_eval(controller.offset, up_extent)
  let prediction = offset + 0.05F
  let dt_value = if dt < 0.0F { 0.0F } else { dt }
  let mut result_translation = @core.Vec3::zero()
  let mut sliding_down_slope = false

  // Rapier parity: `check_and_fix_penetrations` is currently a stub upstream.
  let grounded_at_start = cc3d_real_grounded_info(
      query,
      bodies,
      colliders,
      shape,
      Isometry3(position.translation.add(result_translation), position.rotation),
      up,
      prediction,
      offset,
    ).0
  let mut remaining = translation
  let mut grounded = false
  let mut iters = 0
  while cc3d_real_try_normalize_and_get_length(remaining, 1.0e-5F) is Some(step) {
    if iters >= 20 {
      break
    }
    iters = iters + 1
    let dir = step.0
    let dist = step.1
    let current_pos = @core.Isometry3(
      position.translation.add(result_translation),
      position.rotation,
    )
    let options = @collision.ShapeCastOptions3(dist, false).with_target_distance(
      offset,
    )
    if query.cast_shape(bodies, colliders, current_pos, dir, shape, options)
      is Some(hit) {
      let toi = hit.1.toi()
      let allowed_dist = toi
      let applied = dir.scale(allowed_dist)
      result_translation = result_translation.add(applied)
      remaining = remaining.sub(applied)
      let event_pos = @core.Isometry3(
        position.translation.add(result_translation),
        position.rotation,
      )
      handle_collision({
        handle: hit.0,
        hit: hit.1,
        translation_applied: result_translation,
        translation_remaining: remaining,
        character_pos: event_pos,
      })
      let hit_info = cc3d_real_compute_hit_info(controller, hit.1)
      if controller.autostep is Some(autostep) && hit_info.is_wall {
        if cc3d_real_attempt_autostep(
            query,
            bodies,
            colliders,
            shape,
            event_pos,
            remaining,
            controller,
            (side_extent, up_extent),
            hit.0,
            autostep,
          )
          is Some(step2) {
          remaining = step2.0
          result_translation = result_translation.add(step2.1)
          continue
        }
      }
      let (new_remaining, slid) = cc3d_real_handle_slopes(
        controller, hit_info, translation, remaining,
      )
      remaining = new_remaining
      sliding_down_slope = sliding_down_slope || slid
    } else {
      result_translation = result_translation.add(remaining)
      remaining = @core.Vec3::zero()
      break
    }
    grounded = grounded ||
      cc3d_real_detect_grounded(
        query,
        bodies,
        colliders,
        shape,
        Isometry3(
          position.translation.add(result_translation),
          position.rotation,
        ),
        up,
        prediction,
        offset,
      )
    if !controller.slide {
      break
    }
  }
  if iters == 0 {
    grounded = cc3d_real_grounded_info(
        query, bodies, colliders, shape, position, up, prediction, offset,
      ).0
  }
  if grounded_at_start &&
    !grounded &&
    controller.snap_to_ground is Some(snap_length) {
    let snap_dist = cc3d_real_character_length_eval(snap_length, up_extent)
    if result_translation.dot(up) < -1.0e-5F && snap_dist > 0.0F {
      let current_pos = @core.Isometry3(
        position.translation.add(result_translation),
        position.rotation,
      )
      let down = up.scale(-1.0F)
      let options = @collision.ShapeCastOptions3(snap_dist, false).with_target_distance(
        offset,
      )
      if query.cast_shape(bodies, colliders, current_pos, down, shape, options)
        is Some(hit) {
        result_translation = result_translation.add(down.scale(hit.1.toi()))
        grounded = true
      }
    }
  }
  let final_pos = @core.Isometry3(
    position.translation.add(result_translation),
    position.rotation,
  )
  let end_info = cc3d_real_grounded_info(
    query, bodies, colliders, shape, final_pos, up, prediction, offset,
  )
  if end_info.0 {
    grounded = true
    result_translation = result_translation.add(end_info.1.scale(dt_value))
  }
  {
    translation: result_translation,
    grounded,
    is_sliding_down_slope: sliding_down_slope,
  }
}

///|
pub fn KinematicCharacterController3DReal::solve_character_collision_impulses(
  self : KinematicCharacterController3DReal,
  dt : @core.Real,
  query : @collision.QueryPipeline3DReal,
  bodies : @dynamics.RigidBodySet3D,
  colliders : @collision.ColliderSet3D,
  character_shape : @collision.Shape3D,
  character_mass : @core.Real,
  collisions : Array[CharacterCollision3DReal],
) -> Unit {
  self |> ignore
  character_shape |> ignore
  if dt <= 0.0F {
    return
  }
  // Simplified parity with Rapier: transfer a portion of the character's remaining movement
  // along the collision normal as an impulse applied to the dynamic body hit by the shape-cast.
  for i in 0..