Brikwerk / nxbt

Control your Nintendo Switch through a website, terminal, or macro.
MIT License
814 stars 100 forks source link

Skipping inputs when using macros #127

Open Pegoku opened 1 year ago

Pegoku commented 1 year ago

When i use macros, it sometimes doesn't send a key, why does it happen

Dummydud3 commented 1 year ago

Could you send us the script you're using?

Dummydud3 commented 1 year ago

Also, what command are you using to run th escript? Are you using the Command Line?

Pegoku commented 1 year ago

Could you send us the script you're using?

A 0.1s
1.0s
A 0.1s
1.0s
A 0.1s
1.0s
A 0.1s
1.0s    
LOOP 198
    PLUS 0.1s
    0.4s
    X 0.1s
    0.2s
    LOOP 5
        A 0.1s
        0.1s
    Y && B 0.1s
    0.4s
    LOOP 6
        A 0.1s
        0.1s
    0.25s
Pegoku commented 1 year ago

Also, what command are you using to run th escript? Are you using the Command Line?

Comand Line, in ubuntu 22.04

Dummydud3 commented 1 year ago

Looks good on first look. What kind of device are you using? Last question, are you using an external bluetooth dongle?

Pegoku commented 1 year ago

I'm using an USB Bluetooth from TP-link connected to my pc(running ubuntu 22.04)

Dummydud3 commented 1 year ago

After some troubleshooting, I think the problem is your script. This is the broken segment:

 LOOP 5
        A 0.1s
        0.1s
    Y && B 0.1s
    0.4s 

To press 2 buttons simultaneously, you use a macro command like: Y B 0.1s. So just remove the && in your script and tell me what happens. If you want to see Brikwerks documentation on Macros, here's the file. https://github.com/Brikwerk/nxbt/blob/master/docs/Macros.md

Pegoku commented 1 year ago

After some troubleshooting, I think the problem is your script. This is the broken segment:

 LOOP 5
        A 0.1s
        0.1s
    Y && B 0.1s
    0.4s 

To press 2 buttons simultaneously, you use a macro command like: Y B 0.1s. So just remove the && in your script and tell me what happens. If you want to see Brikwerks documentation on Macros, here's the file. https://github.com/Brikwerk/nxbt/blob/master/docs/Macros.md

changed it and does the same, it doesn't work

Dummydud3 commented 1 year ago

could you send is a demonstration of your script? A recording or replay would be nice as well

Pegoku commented 1 year ago

could you send is a demonstration of your script? A recording or replay would be nice as well

https://imgur.com/a/fgX8KTW

Dummydud3 commented 1 year ago

Unfortunately I don't know much about BotW, but i can tell that random chance seems to be messing with it. Last question (i think), what input was skipped in this clip? P.S. you can text me more directly on discord. username: dummydude_

Pegoku commented 1 year ago

X was skipped

PolarisingEntity commented 1 year ago

I have been trying to find out what causes it too as I had the same problem with inputs being suddenly skipped at seemingly random, just like you.

From what I can see it might be a logic error in controller/server.py, specifically with how command durations longer than one tick are handled. This error occurs in line 184 to 186:

sleep_time = 1/132 - duration_elapsed if sleep_time >= 0: time.sleep(sleep_time)

You might notice that there is no else statement following this for the case that the duration is longer than a tick, as mentioned. To fix the input skipping: insert the following lines and reinstall the local package:

-after line 186: elif (duration_start - time_program_start > startup_time): modified_sleep_time = int(duration_elapsed/(1/132))*1/132 + sleep_time time.sleep(modified_sleep_time)

Also, do note that the refresh rate of a Switch Pro Controller might actually be 132 as this file suggests, so pick the macro input times corresponding to that. I hope that resolves your issue, but I'm in the same boat as you are, so if you find any issues with this, please let me know.

alexargo commented 1 year ago

Was this issue fixed for you after making those changes @PolarisingEntity ? I make the same changes and it doesn't not seem to help.

Brikwerk commented 1 year ago

Sorry this has taken a bit for me to get around to. From my testing, the biggest culprits for input skipping are primarily caused by the following two factors:

  1. The timing behaviour present in the main branch.
  2. Operating system behaviour.

I've attempted to address the first point in the dev branch with an overhauled timing system. The second point is trickier to address and, largely, comes down to process scheduling behaviour in the host OS.

To provide context, NXBT is attempting to share a given CPU's resources with other processes. Maintaining a fast loop with consistent latency can be challenging since NXBT can get preempted (essentially, put to sleep temporarily) by other processes that want a fair share of their time on the CPU.

The problem with the current timing strategy in the main branch is that NXBT is "trusting" the time.sleep function call. Sleeping, unfortunately, can be inaccurate, which results in large latency spikes and skipped or cut-short inputs. The new timing loop in the dev branch uses busy waiting, instead of sleeping, for increased accuracy between ticks. This should hopefully reduce the amount of skipped inputs people are encountering.

As an aside, Windows, unfortunately, seems to be the least friendly platform for running fast loops on (results and discussion here). Inherent timing inaccuracies on Windows seem to result in NXBT skipping inputs more often than on macOS or Linux. Busy waiting still helps on Windows, but there might be some OS quirks that need to be worked around for Windows specifically.

I'm going to make a few more adjustments to the dev branch before merging and slicing off a new version for PyPi. In the meantime, you can test the dev branch (if you want) by installing this version using the following commands:

sudo pip install git+https://github.com/Brikwerk/nxbt@dev
pzl commented 9 months ago

I am running into this as well, with some additional context:

Platform: Linux Running the process with sudo nice -20 so it has a high CPU priority

It is still skipping inputs. I have tried this using the dev branch with the busy-loops instead of sleep, didn't see any difference.

My Macro
0.5s
A 0.1s
0.4s
DPAD_UP 0.1s
0.2s
DPAD_UP 0.1s
0.2s
A 0.2s
1.5s
A 0.2s
0.2s
A 0.2s
3.5s
A 0.3s
1s
DPAD_RIGHT 0.1s
0.2s
DPAD_DOWN 0.1s
0.2s
DPAD_DOWN 0.1s
0.2s
A 0.2s
4s
X 0.2s
0.2s
X 0.2s
0.2s
L 0.2s
0.8s
A 0.2s
0.8s
DPAD_UP 0.25s
0.25s
DPAD_UP 0.25s
0.25s
DPAD_UP 0.25s
0.25s
A 0.2s
1.6s
B 0.2s
2.5s
DPAD_LEFT 0.2s
0.3s
DPAD_DOWN 0.2s
0.3s
DPAD_DOWN 0.2s
0.3s
DPAD_DOWN 0.2s
0.3s
DPAD_DOWN 0.2s
0.3s

I am running that macro in a loop (python while loop, not a macro LOOP). I often get around 2-9 iterations through before it misses a button, and then the sequence is out of sync and I have to kill it.


Edit:

I adjusted the timings in my macro so buttons are held a little longer (but not long enough to register as a long-held button, to move two menu-entries for instance). And I am also running the process as a linux real-time process with chrt -r 60 ... so it can't be preempted. I can get more loops, about 20-40 (using the dev busy-loop branch) before it misses a button press.

Not sure there's much more I can improve for the running environment here, giving it CPU priority on a realtime kernel.

Edited macro
0.2s
A 0.25s
0.4s
DPAD_UP 0.23s
0.2s
DPAD_UP 0.23s
0.2s
A 0.23s
1.5s
A 0.23s
0.2s
A 0.23s
3.5s
A 0.23s
1s
DPAD_RIGHT 0.23s
0.2s
DPAD_DOWN 0.23s
0.2s
DPAD_DOWN 0.23s
0.2s
A 0.23s
4s
X 0.23s
0.2s
X 0.23s
0.2s
L 0.23s
0.8s
A 0.23s
0.6s
DPAD_UP 0.25s
0.25s
DPAD_UP 0.25s
0.25s
DPAD_UP 0.25s
0.25s
A 0.23s
1.4s
B 0.23s
2.5s
DPAD_LEFT 0.23s
0.3s
DPAD_DOWN 0.23s
0.3s
DPAD_DOWN 0.23s
0.3s
DPAD_DOWN 0.23s
0.3s
DPAD_DOWN 0.23s
0.3s