buttplugio / buttplug

Rust Implementation of the Buttplug Sex Toy Control Protocol

Home Page:https://buttplug.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Command buffering/update error in protocols that require match_all for generic commands (Satisfyer, WeVibe, etc)

qdot opened this issue · comments

commented

Describe the bug

  1. Start Intiface Central, start server, scan for devices on devices tab
  2. Connect devices that have protocols that require keepalives (Satisfyer, WeVibe, maybe Mysteryvibe, etc), as well as ones that don't (Lovense, OhMiBod, etc)
  3. Move sliders, confirm that toys respond
  4. Start Ultrakill w/ UKButt mod
  5. Start game, shoot things

Expected behavior

All toys should vibrate

Actual behavior

Toys that don't require keepalives work fine. Toys that do require keepalives have a massive amount of latency (on the order of over a minute sometimes?!), and flood logs with messages about "No commands generated for incoming device packet". If the server is stopped or game is disconnected, the Intiface Central logs flood with errors about not being able to contact the device. The devices may also start vibrating after the server is shut down, which makes it seem like we're hitting a command buffering issue in the OS?!

Additional context

This is weird as hell, since things seem fine when using the device panel sliders, but the game itself makes them go apeshit. While the GHR currently has its own issues with crashing on Windows 11, connecting it to intiface central and just using base vibration adjustment works fine.

commented

Ok, was wrong about my initial reasoning here. This wasn't about keepalives, because wevibe doesn't have one of those. The shared trait across all of the broken protocols was requiring match_all in the generic command manager.

This means we've been broken across Satisfyer, Magic Motion, WeVibe, and Lovehoney for a while. XInput also has this but we'll never saturate that, so it wasn't noticable.

When a command packet is generated that contains to new updates for a device, the GCM should return an empty array. This is true for instances where match_all was false. If match_all was true, we'd return command packets regardless if it they contained all repeated commands or not.

The fix is to ignore match_all until right before we're about to return, and if we're already returning a command packet with new values, fill in all of the None values with the current speed values.

So why did this specifically fail in Ultrakill? Well, ultrakill sends updates on every render loop, which is 60hz (if not more? not sure if it's uncapped). This meant we were flooding devices that could take maybe 8-10hz updates on a good day with 60hz worth of updates. For the WeVibe and a couple of others, they also require WriteWithResponse, meaning we were sending shit THEN having to wait at the OS level for responses, which is why we'd get a huge flood of errors if we just disconnected the server (this is another bug, all of those should've cancelled.).