use crate::{
client::ActorBlueprint,
geom::{Location, Transform, Vector3D},
rpc::{
ActorId, TrafficLightState, VehicleAckermannControl, VehicleControl, VehicleLightState,
VehiclePhysicsControl, WalkerControl,
},
};
use autocxx::WithinUniquePtr;
use carla_sys::carla_rust::{client::FfiCommandBatch, geom::FfiVector3D};
use cxx::UniquePtr;
pub enum Command {
SpawnActor {
blueprint: ActorBlueprint,
transform: Transform,
parent: Option<ActorId>,
do_after: Vec<Command>,
},
DestroyActor { actor_id: ActorId },
ApplyVehicleControl {
actor_id: ActorId,
control: VehicleControl,
},
ApplyVehicleAckermannControl {
actor_id: ActorId,
control: VehicleAckermannControl,
},
ApplyWalkerControl {
actor_id: ActorId,
control: WalkerControl,
},
ApplyVehiclePhysicsControl {
actor_id: ActorId,
physics_control: VehiclePhysicsControl,
},
ApplyTransform {
actor_id: ActorId,
transform: Transform,
},
ApplyLocation {
actor_id: ActorId,
location: Location,
},
ApplyWalkerState {
actor_id: ActorId,
transform: Transform,
speed: f32,
},
ApplyTargetVelocity {
actor_id: ActorId,
velocity: Vector3D,
},
ApplyTargetAngularVelocity {
actor_id: ActorId,
angular_velocity: Vector3D,
},
ApplyImpulse {
actor_id: ActorId,
impulse: Vector3D,
},
ApplyForce { actor_id: ActorId, force: Vector3D },
ApplyAngularImpulse {
actor_id: ActorId,
impulse: Vector3D,
},
ApplyTorque { actor_id: ActorId, torque: Vector3D },
SetSimulatePhysics { actor_id: ActorId, enabled: bool },
SetEnableGravity { actor_id: ActorId, enabled: bool },
SetAutopilot {
actor_id: ActorId,
enabled: bool,
tm_port: u16,
},
ShowDebugTelemetry { actor_id: ActorId, enabled: bool },
SetVehicleLightState {
actor_id: ActorId,
light_state: VehicleLightState,
},
ConsoleCommand { command: String },
SetTrafficLightState {
actor_id: ActorId,
state: TrafficLightState,
},
}
impl Command {
pub fn spawn_actor(
blueprint: ActorBlueprint,
transform: Transform,
parent: Option<ActorId>,
) -> Self {
Self::SpawnActor {
blueprint,
transform,
parent,
do_after: Vec::new(),
}
}
pub fn then(mut self, command: Command) -> Self {
if let Self::SpawnActor {
ref mut do_after, ..
} = self
{
do_after.push(command);
}
self
}
pub fn destroy_actor(actor_id: ActorId) -> Self {
Self::DestroyActor { actor_id }
}
pub fn apply_vehicle_control(actor_id: ActorId, control: VehicleControl) -> Self {
Self::ApplyVehicleControl { actor_id, control }
}
pub fn apply_walker_control(actor_id: ActorId, control: WalkerControl) -> Self {
Self::ApplyWalkerControl { actor_id, control }
}
pub fn apply_transform(actor_id: ActorId, transform: Transform) -> Self {
Self::ApplyTransform {
actor_id,
transform,
}
}
pub fn set_autopilot(actor_id: ActorId, enabled: bool, tm_port: u16) -> Self {
Self::SetAutopilot {
actor_id,
enabled,
tm_port,
}
}
pub fn console_command(command: String) -> Self {
Self::ConsoleCommand { command }
}
pub(crate) fn add(&self, batch: &mut UniquePtr<FfiCommandBatch>) {
use carla_sys::carla_rust::client::FfiCommandBatch as Batch;
match self {
Self::SpawnActor {
blueprint,
transform,
parent,
do_after,
} => {
let desc = blueprint.inner.MakeActorDescription().within_unique_ptr();
Batch::AddSpawnActor(
batch.pin_mut(),
desc,
transform.as_ffi(),
parent.unwrap_or(0),
);
if !do_after.is_empty() {
let mut sub_batch = FfiCommandBatch::new().within_unique_ptr();
for cmd in do_after {
cmd.add(&mut sub_batch);
}
Batch::AttachDoAfterToLastSpawn(batch.pin_mut(), sub_batch);
}
}
Self::DestroyActor { actor_id } => {
Batch::AddDestroyActor(batch.pin_mut(), *actor_id);
}
Self::ApplyVehicleControl { actor_id, control } => {
Batch::AddApplyVehicleControl(batch.pin_mut(), *actor_id, control);
}
Self::ApplyVehicleAckermannControl { actor_id, control } => {
Batch::AddApplyVehicleAckermannControl(batch.pin_mut(), *actor_id, control);
}
Self::ApplyWalkerControl { actor_id, control } => {
Batch::AddApplyWalkerControl(batch.pin_mut(), *actor_id, control);
}
Self::ApplyVehiclePhysicsControl {
actor_id,
physics_control,
} => {
let ffi_physics = physics_control.to_cxx();
Batch::AddApplyVehiclePhysicsControl(batch.pin_mut(), *actor_id, &ffi_physics);
}
Self::ApplyTransform {
actor_id,
transform,
} => {
Batch::AddApplyTransform(batch.pin_mut(), *actor_id, transform.as_ffi());
}
Self::ApplyLocation { actor_id, location } => {
Batch::AddApplyLocation(batch.pin_mut(), *actor_id, location.as_ffi());
}
Self::ApplyWalkerState {
actor_id,
transform,
speed,
} => {
Batch::AddApplyWalkerState(batch.pin_mut(), *actor_id, transform.as_ffi(), *speed);
}
Self::ApplyTargetVelocity { actor_id, velocity } => {
unsafe {
let cpp_vec = &*(velocity.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyTargetVelocity(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::ApplyTargetAngularVelocity {
actor_id,
angular_velocity,
} => {
unsafe {
let cpp_vec = &*(angular_velocity.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyTargetAngularVelocity(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::ApplyImpulse { actor_id, impulse } => {
unsafe {
let cpp_vec = &*(impulse.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyImpulse(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::ApplyForce { actor_id, force } => {
unsafe {
let cpp_vec = &*(force.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyForce(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::ApplyAngularImpulse { actor_id, impulse } => {
unsafe {
let cpp_vec = &*(impulse.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyAngularImpulse(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::ApplyTorque { actor_id, torque } => {
unsafe {
let cpp_vec = &*(torque.as_ffi() as *const FfiVector3D
as *const carla_sys::carla::geom::Vector3D);
Batch::AddApplyTorque(batch.pin_mut(), *actor_id, cpp_vec);
}
}
Self::SetSimulatePhysics { actor_id, enabled } => {
Batch::AddSetSimulatePhysics(batch.pin_mut(), *actor_id, *enabled);
}
Self::SetEnableGravity { actor_id, enabled } => {
Batch::AddSetEnableGravity(batch.pin_mut(), *actor_id, *enabled);
}
Self::SetAutopilot {
actor_id,
enabled,
tm_port,
} => {
Batch::AddSetAutopilot(batch.pin_mut(), *actor_id, *enabled, *tm_port);
}
Self::ShowDebugTelemetry { actor_id, enabled } => {
Batch::AddShowDebugTelemetry(batch.pin_mut(), *actor_id, *enabled);
}
Self::SetVehicleLightState {
actor_id,
light_state,
} => {
unsafe {
let flag_value = std::mem::transmute_copy::<_, u32>(light_state);
Batch::AddSetVehicleLightState(batch.pin_mut(), *actor_id, flag_value);
}
}
Self::ConsoleCommand { command } => {
use cxx::let_cxx_string;
let_cxx_string!(cmd = command);
Batch::AddConsoleCommand(batch.pin_mut(), &cmd);
}
Self::SetTrafficLightState { actor_id, state } => {
unsafe {
let state_value = std::mem::transmute_copy::<_, u8>(state);
Batch::AddSetTrafficLightState(batch.pin_mut(), *actor_id, state_value);
}
}
}
}
}