Search Unity

Can't retrieve value from a dictionary

Discussion in 'Scripting' started by TitoOliveira, Jun 30, 2020.

  1. TitoOliveira

    TitoOliveira

    Joined:
    Aug 4, 2014
    Posts:
    79
    I'm making a custom input buffer for my game, buffering the frames from every input on my input asset (the one generated by Unity's new input system).
    When i initialize the buffer, the keys of the dictionary are actions in my actionMap, like so:

    Code (CSharp):
    1. actions = controls.asset.actionMaps[0].actions.ToArray(); //get all actions in the input asset
    2.         buffer = new Dictionary<InputAction, InputBufferItem[]>();
    3.  
    4.         for (int a = 0; a < actions.Length; a++) //foreach InputAction in actions, add a new item in the dictionary
    5.         {
    6.             InputBufferItem[] items = new InputBufferItem[size];
    7.             for (int b = 0; b < size; b++)
    8.             {
    9.                 items[b] = new InputBufferItem();
    10.             }
    11.  
    12.             buffer.Add(actions[a], items);
    13.         }
    Somewhere else i have a case where i need to check a certain value. So i'm retrieving the key string from the same place i initialized the buffer in order to retrieve the value associated with that key:

    Code (CSharp):
    1.         InputAction run = controls.asset.actionMaps[0].actions[0];
    2.         InputBufferItem[] buffer = inputBuffer.buffer[run];
    The issue is that is not returning what i need, it doesn't find a corresponding key. When i debug the values this is what i get in return:
    run = "Player/Run[/Keyboard/a,/Keyboard/d,/Keyboard/leftArrow,/Keyboard/rightArrow]"
    but the key that it should retrieve looks like this on the dict = "[Player/Run[/Keyboard/a,/Keyboard/d,/Keyboard/leftArrow,/Keyboard/rightArrow], InputBufferItem[]]"

    As far as i can tell, that [ at the start of the string on the dictionary is throwing things off. But i'm not sure.
    What is going on?
     
  2. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    The [ at the start isn't part of the key, it's part of the string representation of the dictionary key pair.

    Make sure that your retrieval code is being called after your initializing code.
     
    TitoOliveira likes this.
  3. TitoOliveira

    TitoOliveira

    Joined:
    Aug 4, 2014
    Posts:
    79
    I'm pretty sure it is. Everything is being initialized on Awake, and the retrieval is on the Update loop
     
  4. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    How do InputActions implement the concept of equality? Does their concept of equality match the one you're trying to use?

    Any object used as a key in a dictionary needs to be "constant" while its in the dictionary, in the sense that its hash value must not change, and the answer to "is this key equal to X" must not change for any X. And the object you use to look up the key must compare as being equal to the object you used when inserting that value into the Dictionary in the first place.

    I haven't used the new input system. This documentation doesn't list any overrides for Equals or GetHashCode, so I imagine it's using inherited versions, which I imagine are testing reference equality. (Though I'm not certain.) Are you generating your InputActions in such a way that the keys you use to look stuff up in the dictionary are guaranteed to be reference-equal to the keys you used to store stuff in the dictionary?

    What actual result are you getting when you run the last code snippet in your OP? Does it throw an error? If so, what's the exact error message, and which line does it get thrown from? If not, what is the value of "buffer" when you finish?


    EDIT: Added the hyperlink I forgot the first time.
     
    Last edited: Jun 30, 2020
    TitoOliveira and PraetorBlue like this.
  5. TitoOliveira

    TitoOliveira

    Joined:
    Aug 4, 2014
    Posts:
    79
    I'm not sure, i'm assuming yes, since when i debug the values it never changes.

    It throws
    KeyNotFoundException: The given key was not present in the dictionary.
    System.Collections.Generic.Dictionary`

    The line it throws is the exact line in the snippet where i'm trying to retrieve the value.

    And the values are the ones mentioned in the end of the post

    run = "Player/Run[/Keyboard/a,/Keyboard/d,/Keyboard/leftArrow,/Keyboard/rightArrow]"
    key that it should retrieve looks like this on the dictionary = "[Player/Run[/Keyboard/a,/Keyboard/d,/Keyboard/leftArrow,/Keyboard/rightArrow], InputBufferItem[]]"

    At least the strings match
    https://imgur.com/a/RTa24sF

    I should probably refactor this to not use a dictionary, but i also want to know what is going on
     
    Last edited: Jun 30, 2020
  6. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    I missed that your dictionary key is not a
    string
    . This means that the string representation of the InputAction is irrelevant, and it will instead look at object reference equality (unless you override the Equals method).

    When you debug the values, the string representation may not have changed, but that doesn't mean that the InputAction that you fill the dictionary with is the same InputAction that you check it with.
     
    Last edited: Jun 30, 2020
    TitoOliveira likes this.
  7. TitoOliveira

    TitoOliveira

    Joined:
    Aug 4, 2014
    Posts:
    79
    I see, makes sense.
    Guess i should just get the string and see how that goes
     
  8. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,317
    I'm not familiar with the new Unity input system, so I'm afraid my brain is wrapping around this slower than usual. I've just had another thought:

    The usual modus operandi for Unity functions is that they create arrays on the fly when you request them. That means that it is likely that when you call asset.actionMaps or ActionMap.actions that it is actually a copy of the underlying map, and doesn't contain the same InputAction instances every time.
     
    TitoOliveira likes this.
  9. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,908
    It looks like InputAction has a Guid field called id: https://docs.unity3d.com/Packages/c...n.html#UnityEngine_InputSystem_InputAction_id

    In the docs this is described as: "A stable, unique identifier for the action."

    I would try using this id as your dictionary key instead of the InputAction object itself. It's possible you don't get the same object from subsequent searches of the action maps. This id will likely be your best candidate for a stable unique identifier.
     
    Antistone, TitoOliveira and Madgvox like this.
  10. TitoOliveira

    TitoOliveira

    Joined:
    Aug 4, 2014
    Posts:
    79
    Guess that's a solved thread.
    Thanks everyone