mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-13 17:25:36 +02:00
More multi-controller fixes, better controller polling logic, clean up dead relay code
This commit is contained in:
@@ -29,10 +29,8 @@ impl ControllerInput {
|
||||
client: &vimputti::client::VimputtiClient,
|
||||
) -> Result<Self> {
|
||||
let config = controller_string_to_type(&controller_type)?;
|
||||
Ok(Self {
|
||||
config: config.clone(),
|
||||
device: client.create_device(config).await?,
|
||||
})
|
||||
let device = client.create_device(config.clone()).await?;
|
||||
Ok(Self { config, device })
|
||||
}
|
||||
|
||||
pub fn device_mut(&mut self) -> &mut vimputti::client::VirtualController {
|
||||
@@ -121,9 +119,60 @@ async fn command_loop(
|
||||
slot.session_id == session_id && slot.session_slot == session_slot as u32
|
||||
})
|
||||
.map(|(slot_num, _)| *slot_num);
|
||||
let slot = existing_slot.or_else(|| get_free_slot(&controllers));
|
||||
|
||||
if let Some(slot) = slot {
|
||||
if let Some(existing_slot) = existing_slot {
|
||||
if let Some(controller_slot) = controllers.get_mut(&existing_slot) {
|
||||
let rumble_tx = rumble_tx.clone();
|
||||
let attach_tx = attach_tx.clone();
|
||||
|
||||
controller_slot
|
||||
.controller
|
||||
.device_mut()
|
||||
.on_rumble(move |strong, weak, duration_ms| {
|
||||
let _ = rumble_tx.try_send((
|
||||
existing_slot,
|
||||
strong,
|
||||
weak,
|
||||
duration_ms,
|
||||
data.session_id.clone(),
|
||||
));
|
||||
})
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::warn!(
|
||||
"Failed to register rumble callback for slot {}: {}",
|
||||
existing_slot,
|
||||
e
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Return to attach_tx what slot was assigned
|
||||
let attach_info = ProtoControllerAttach {
|
||||
id: data.id.clone(),
|
||||
session_slot: existing_slot as i32,
|
||||
session_id: session_id.clone(),
|
||||
};
|
||||
|
||||
match attach_tx.send(attach_info).await {
|
||||
Ok(_) => {
|
||||
tracing::info!(
|
||||
"Controller {} re-attached to slot {} (session: {})",
|
||||
data.id,
|
||||
existing_slot,
|
||||
session_id
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Failed to send re-attach info for slot {}: {}",
|
||||
existing_slot,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(slot) = get_free_slot(&controllers) {
|
||||
if let Ok(mut controller) =
|
||||
ControllerInput::new(data.id.clone(), &vimputti_client).await
|
||||
{
|
||||
@@ -133,7 +182,13 @@ async fn command_loop(
|
||||
controller
|
||||
.device_mut()
|
||||
.on_rumble(move |strong, weak, duration_ms| {
|
||||
let _ = rumble_tx.try_send((slot, strong, weak, duration_ms, data.session_id.clone()));
|
||||
let _ = rumble_tx.try_send((
|
||||
slot,
|
||||
strong,
|
||||
weak,
|
||||
duration_ms,
|
||||
data.session_id.clone(),
|
||||
));
|
||||
})
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -190,65 +245,10 @@ async fn command_loop(
|
||||
if controllers.remove(&(data.session_slot as u32)).is_some() {
|
||||
tracing::info!("Controller detached from slot {}", data.session_slot);
|
||||
} else {
|
||||
tracing::warn!("No controller found in slot {} to detach", data.session_slot);
|
||||
}
|
||||
}
|
||||
Payload::ControllerButton(data) => {
|
||||
if let Some(controller) = controllers.get(&(data.session_slot as u32)) {
|
||||
if let Some(button) = vimputti::Button::from_ev_code(data.button as u16) {
|
||||
let device = controller.controller.device();
|
||||
device.button(button, data.pressed);
|
||||
device.sync();
|
||||
}
|
||||
} else {
|
||||
tracing::warn!("Controller slot {} not found for button event", data.session_slot);
|
||||
}
|
||||
}
|
||||
Payload::ControllerStick(data) => {
|
||||
if let Some(controller) = controllers.get(&(data.session_slot as u32)) {
|
||||
let device = controller.controller.device();
|
||||
if data.stick == 0 {
|
||||
// Left stick
|
||||
device.axis(vimputti::Axis::LeftStickX, data.x);
|
||||
device.sync();
|
||||
device.axis(vimputti::Axis::LeftStickY, data.y);
|
||||
} else if data.stick == 1 {
|
||||
// Right stick
|
||||
device.axis(vimputti::Axis::RightStickX, data.x);
|
||||
device.sync();
|
||||
device.axis(vimputti::Axis::RightStickY, data.y);
|
||||
}
|
||||
device.sync();
|
||||
} else {
|
||||
tracing::warn!("Controller slot {} not found for stick event", data.session_slot);
|
||||
}
|
||||
}
|
||||
Payload::ControllerTrigger(data) => {
|
||||
if let Some(controller) = controllers.get(&(data.session_slot as u32)) {
|
||||
let device = controller.controller.device();
|
||||
if data.trigger == 0 {
|
||||
// Left trigger
|
||||
device.axis(vimputti::Axis::LowerLeftTrigger, data.value);
|
||||
} else if data.trigger == 1 {
|
||||
// Right trigger
|
||||
device.axis(vimputti::Axis::LowerRightTrigger, data.value);
|
||||
}
|
||||
device.sync();
|
||||
} else {
|
||||
tracing::warn!("Controller slot {} not found for trigger event", data.session_slot);
|
||||
}
|
||||
}
|
||||
Payload::ControllerAxis(data) => {
|
||||
if let Some(controller) = controllers.get(&(data.session_slot as u32)) {
|
||||
let device = controller.controller.device();
|
||||
if data.axis == 0 {
|
||||
// dpad x
|
||||
device.axis(vimputti::Axis::DPadX, data.value);
|
||||
} else if data.axis == 1 {
|
||||
// dpad y
|
||||
device.axis(vimputti::Axis::DPadY, data.value);
|
||||
}
|
||||
device.sync();
|
||||
tracing::warn!(
|
||||
"No controller found in slot {} to detach",
|
||||
data.session_slot
|
||||
);
|
||||
}
|
||||
}
|
||||
Payload::ClientDisconnected(data) => {
|
||||
@@ -274,6 +274,125 @@ async fn command_loop(
|
||||
}
|
||||
}
|
||||
}
|
||||
Payload::ControllerStateBatch(data) => {
|
||||
if let Some(controller) = controllers.get(&(data.session_slot as u32)) {
|
||||
let device = controller.controller.device();
|
||||
|
||||
// Handle inputs based on update type
|
||||
if data.update_type == 0 {
|
||||
// FULL_STATE: Update all values
|
||||
let _ = device.sync().await;
|
||||
for (btn_code, pressed) in data.button_changed_mask {
|
||||
if let Some(button) = vimputti::Button::from_ev_code(btn_code as u16) {
|
||||
let _ = device.button(button, pressed).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if let Some(x) = data.left_stick_x {
|
||||
let _ = device.axis(vimputti::Axis::LeftStickX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(y) = data.left_stick_y {
|
||||
let _ = device.axis(vimputti::Axis::LeftStickY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(x) = data.right_stick_x {
|
||||
let _ = device.axis(vimputti::Axis::RightStickX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(y) = data.right_stick_y {
|
||||
let _ = device.axis(vimputti::Axis::RightStickY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(value) = data.left_trigger {
|
||||
let _ = device.axis(vimputti::Axis::LowerLeftTrigger, value).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(value) = data.right_trigger {
|
||||
let _ = device.axis(vimputti::Axis::LowerRightTrigger, value).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(x) = data.dpad_x {
|
||||
let _ = device.axis(vimputti::Axis::DPadX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
if let Some(y) = data.dpad_y {
|
||||
let _ = device.axis(vimputti::Axis::DPadY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
} else {
|
||||
// DELTA: Only update changed values
|
||||
if let Some(changed_fields) = data.changed_fields {
|
||||
let _ = device.sync().await;
|
||||
if (changed_fields & (1 << 0)) != 0 {
|
||||
for (btn_code, pressed) in data.button_changed_mask {
|
||||
if let Some(button) =
|
||||
vimputti::Button::from_ev_code(btn_code as u16)
|
||||
{
|
||||
let _ = device.button(button, pressed).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 1)) != 0 {
|
||||
if let Some(x) = data.left_stick_x {
|
||||
let _ = device.axis(vimputti::Axis::LeftStickX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 2)) != 0 {
|
||||
if let Some(y) = data.left_stick_y {
|
||||
let _ = device.axis(vimputti::Axis::LeftStickY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 3)) != 0 {
|
||||
if let Some(x) = data.right_stick_x {
|
||||
let _ = device.axis(vimputti::Axis::RightStickX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 4)) != 0 {
|
||||
if let Some(y) = data.right_stick_y {
|
||||
let _ = device.axis(vimputti::Axis::RightStickY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 5)) != 0 {
|
||||
if let Some(value) = data.left_trigger {
|
||||
let _ =
|
||||
device.axis(vimputti::Axis::LowerLeftTrigger, value).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 6)) != 0 {
|
||||
if let Some(value) = data.right_trigger {
|
||||
let _ =
|
||||
device.axis(vimputti::Axis::LowerRightTrigger, value).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 7)) != 0 {
|
||||
if let Some(x) = data.dpad_x {
|
||||
let _ = device.axis(vimputti::Axis::DPadX, x).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
if (changed_fields & (1 << 8)) != 0 {
|
||||
if let Some(y) = data.dpad_y {
|
||||
let _ = device.axis(vimputti::Axis::DPadY, y).await;
|
||||
let _ = device.sync().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Controller slot {} not found for state batch event",
|
||||
data.session_slot
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
//no-op
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user