matjlars / godot-multiplayer-input

This Godot addon provides two simple APIs for using normal Input Actions, but spread out across a Keyboard player and up to 8 Joypad players.
MIT License
104 stars 6 forks source link

Unplugging controllers crashes #2

Closed willerxxmiller closed 1 year ago

willerxxmiller commented 1 year ago

It seems to crash when a controller get unplugged. I think the actions_to_erase array wasn't being added to correctly.

func _delete_actions_for_device(device: int):
    device_actions.erase(device)
    var actions_to_erase = []
    var device_num_str = str(device)

    # figure out which actions should be erased
    for action in InputMap.get_actions():
        var action_str = String(action)
        var maybe_device = action_str.substr(0, device_num_str.length())
        if maybe_device == device_num_str:
            actions_to_erase = action                              <------Old and I think broken
            actions_to_erase.append(action)                   <------New and I think fixed

    # now actually erase them
    # this is done separately so I'm not erasing from the collection I'm looping on
    # not sure if this is necessary but whatever, this is safe
    for action in actions_to_erase:
        InputMap.erase_action(action)

This will still cause an error if a player was spawned since there are no longer actions associated with it now. I'm looking into solutions for that. Maybe adding a "pause" to the game until a controller is reconnected, or maybe a check at the top of the player processor to confirm that the associated device is still connected before looking for inputs.

willerxxmiller commented 1 year ago

Love the module though. very helpful!

willerxxmiller commented 1 year ago

I don't love this solution but here is what I came up with:

in multiplayer_input.gd add:

func is_device_still_connected(device: int) -> bool:
    # exit if not gamepad
    if device == -1:
        return true

    # check for device in action list
    for devices in device_actions:
        if devices == device:
            return true

    return false

in device_input.gd add:

func is_device_still_connected() -> bool:

    return MultiplayerInput.is_device_still_connected(device)

in the player script check for device before any other inputs:

# check for device

    if input.is_device_still_connected():

        # handle inputs.
matjlars commented 1 year ago

Ok I have looked at this. At first I was confused because this is all sounding extremely familiar. Now I refreshed myself, I think you must have an old version of the code. Check out this commit that is already merged into main that does very similar things to what you are proposing: https://github.com/matjlars/godot-multiplayer-input/commit/930ae9337b4de347251c5f12c329df46bdf14552

I figured out the root cause! I didn't realize this, but I should've manually updated the commit hash in the Godot Asset Lib website. You had downloaded the original version, before I made that update.

I have just submitted the edit now, so as soon as that is accepted, the newest version should be available via the AssetLib tab. Until then, feel free to download the latest .gd files from this repo and replace the ones in your project.

Thanks for pointing this out! This is my only package on the Godot Asset Lib, and my only experience with a different package management system is with packagist which manages composer packages for PHP and that one has a Github integration so it automatically updates when I merge something into main. TIL!

Thanks again!

I'll close this issue but feel free to re-open it or keep talking

willerxxmiller commented 1 year ago

ah, you're right I was using an old version. Sorry, new to godot and didn't think to double check the code here.

matjlars commented 1 year ago

No problem! I'm new to having an asset on the asset lib :) Thanks again for helping me learn about that.