TASEmulators / BizHawk

BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as full screen, and joypad support in addition to full rerecording and debugging tools for all system cores.
http://tasvideos.org/BizHawk.html
Other
2.21k stars 386 forks source link

Lua joypad.setanalog sets analog indefinitely #2310

Open Sirius902 opened 4 years ago

Sirius902 commented 4 years ago

Summary

I would expect joypad.setanalog to only set analog inputs for the current frame as stated here but it seems to set the analog input indefinitely. The only way I have found to give control back to the user is by overriding the analog position using the Virtual Pad tool. I am testing this on the Mupen64plus core with Ocarina of Time.

Repro

If you run the script below on an N64 game you will walk forward forever instead of only for one frame.

joypad.setanalog({
    ['P1 X Axis'] = 0,
    ['P1 Y Axis'] = 127,
})

Versions Tested

RetroEdit commented 4 years ago

joypad.setanalog

  • void joypad.setanalog(nluatable controls, [object controller = null])
  • sets the given analog controls to their provided values for the current frame. Note that unlike set() there is only the logic of overriding with the given value.

Based on the second sentence, you're supposed to override back with something like joypad.setanalog({['P1 X Axis'] = 0, ['P1 Y Axis'] = 0}) when you want the analog sticks to be neutral again.

Sirius902 commented 4 years ago

I have tried that but it still does not return control to the user, any inputs on the controller after the script are ignored.

Sirius902 commented 4 years ago

@RetroEdit

RetroEdit commented 4 years ago

If you continually set it to neutral every frame, then yes, it will override the user's inputs. If you only set it to neutral the first frame you want it to be neutral, and then don't use joypad.set on later inputs, then you won't shouldn't have this problem.

Sirius902 commented 4 years ago

@RetroEdit But even if I just run this script you lose control of the analog stick indefinitely.

joypad.setanalog({
    ['P1 X Axis'] = 0,
    ['P1 Y Axis'] = 0,
})
RetroEdit commented 4 years ago

I see. I'll have a look.

EDIT: I'm not too sure either way on this one. Someone else will have to have a look.

Gikkman commented 4 years ago

One solution could be to set the input as an empty string to regain control, similar to what I did in this script:

https://github.com/TASVideos/BizHawk/blob/master/Assets/Lua/JoypadIntersection.lua

I can try to remember to test it tonight and report back what I find

Gikkman commented 4 years ago

Alright, something has changed in regards to this in the least few releases. In my old 2.3.2 version of Bizhawk, doing this:

joypad.setanalog({ ['X Axis'] = '', ['Y Axis'] = '', }, 1)

Would allow you to reset the sticks, and give control back to the user. But doing it in 2.4.2 and 2.5 gives an exception. The exception message isn't helpful though, it just says "A .NET exception occured in user-code"

For reference, here is my scipt that works in 2.3.2 but not in later:

local forward = { ['X Axis'] = 0, ['Y Axis'] = 127, }
local resetA = { ['X Axis'] = '', ['Y Axis'] = '', }
local shouldForward = false

local reset = joypad.get(1)
for k,v in pairs(reset) do
    reset[k] = null
end

event.unregisterbyname('a')
event.unregisterbyname('e')

event.onframestart( function()
    if shouldForward == true then
        joypad.setanalog(forward, 1)
    end
end, 's' )

event.onframeend( function()    
    if shouldForward == false then
        joypad.setanalog(resetA, 1)
    end
end, 'e' )

--------------------------------------
--             Main loop            --
--------------------------------------
while true do
    if emu.framecount() % 180 == 0 then
        shouldForward = not shouldForward
        print(shouldForward)
    end
    emu.frameadvance()
end
YoshiRulz commented 4 years ago

Probably introduced by 1042f746f with an incomplete fix in 0f7d29210.

edit: Fixed as below. To reiterate: pass a key-value pair where the value is not a double e.g. {["axisName"] = ""} to not override or undo a previously set override of an axis. I didn't check but from memory a key-value pair in a table where the value is nil is equivalent to not including that pair—use an empty string. Omitting a key from the table passed to joypad.setanalog will continue to use the previously set override if one was set in a previous call.

Morilli commented 2 months ago

Maybe the documentation should be fixed to not say the same as the set() function when it does something completely different?