Search Unity

Unity Multiplayer [Command] Inheritance Heirarchy Index Mismatch Bug

Discussion in 'Connected Games' started by Zullar, Oct 7, 2015.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    The Bug:
    I have a character GameObject with 5 NetworkBehavior Feat (ability/action) scripts.
    When I call [Command] CmdUseFeat() for feat #4 on the client, it calls CmdUseFeat() for feat #3 on the server (bugged).

    Additional Details:
    The bug does not occur on the host, only local clients (I have not tested with remote client).

    The 5 feats are attached to a player prefab.

    Calling CmdUseFeat #1 on client calls Calling CmdUseFeat #1 on server.
    Calling CmdUseFeat #2 on client calls Calling CmdUseFeat #2 on server.
    Calling CmdUseFeat #3 on client calls Calling CmdUseFeat #3 on server.
    Calling CmdUseFeat #4 on client calls Calling CmdUseFeat #3 on server.
    Calling CmdUseFeat #5 on client calls Calling CmdUseFeat #3 on server.

    Re-ordering the feats on the prefab hierarchy swaps the problem. For example if I move feat #5 to the #1 position then it works properly, but the new #5 feat now is bugged out.

    If I was to guess I would think the bug has something to do with the use inheritance of an Abstract Feat class with the [Command] CmdUseFeat() method... or possibly due to overriding of the [Command] method. But that's just a guess. I'll keep working to narrow down the specific setup to replicate. Is anybody else having this bug? Any tricks to fix?

    The full code is too long to paste, so I posted some example pseudo code of the bug. DebugDisplayFeatName() will display the feats name... and it shows the Client/Host [Command] index mismatch (see comments below).

    Code (csharp):
    1.  
    2. protected override void OnKeyDown()
    3. {
    4.    DebugDisplayFeatName();  //This will display "FeatFireball" on the client (Feat index #4)
    5.    CmdUseFeat();
    6. }
    7.  
    8. [Command]
    9. protected override void CmdUseFeat ()
    10. {
    11.    DebugDisplayFeatName(); //This will display "FeatTeleport" on the server (Feat index #3)
    12. }
    13.  
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    commands as virtual functions is not supported.
     
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    Attached is simplified code to replicate the bug.

    I removed the virtual [Command] functions and the bug persists. I did more testing and it seems that when [Commands] are used that are non-unique (i.e. when there is several instances of the same NetworkBehavior script attached to a GameObject, or a parent class with multiple child classes attached to the same GameObject) then incorrectly calls the [Command] on the 1st instance in the hierarchy when called from the localClient regardless of which instance calls the [Command].

    To replicate bug place 3 instances of this TestCommand script onto a player object. They will be given unique ID's of 1, 2, and 3. Pressing keys 1, 2, and 3 calls the [Command] on each respective instance. Results are as follows.

    On the host
    Pressing key #1 calls [Command] for instance #1
    Pressing key #2 calls [Command] for instance #2
    Pressing key #3 calls [Command] for instance #3

    On the localClient
    Pressing key #1 calls [Command] for instance #1
    Pressing key #2 calls [Command] for instance #1 (bugged)
    Pressing key #3 calls [Command] for instance #1 (bugged)

    The debug output shows the bug where calling a command on index 3 calls the [Command] on index 1
    OnClient: "Key pressed for uniqueID=3"
    OnHost: "CmdTest called for uniqueID=1"

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking; //needed for NetworkBehavior
    5.  
    6. public class TestCommand : NetworkBehaviour
    7. {
    8.     private static int IDcounter;
    9.  
    10.     [SyncVar]
    11.     public int uniqueID;
    12.  
    13.     private void Awake()
    14.     {
    15.         IDcounter = 0;
    16.     }
    17.  
    18.     private void Start()
    19.     {
    20.         if(isServer)
    21.         {
    22.             uniqueID = ++IDcounter;
    23.             Debug.Log("uniqueID=" + uniqueID);
    24.         }
    25.     }
    26.  
    27.     private void Update()
    28.     {
    29.         if(isLocalPlayer)
    30.         {
    31.             if(Input.GetKeyDown(keyCode))
    32.             {
    33.                 Debug.Log("Key pressed for uniqueID=" + uniqueID);
    34.                 CmdTest();
    35.             }
    36.         }
    37.     }
    38.  
    39.     [Command]
    40.     private void CmdTest()
    41.     {
    42.         Debug.Log("CmdTest called for uniqueID=" + uniqueID);
    43.     }
    44.  
    45.     private KeyCode keyCode
    46.     {
    47.         get
    48.         {
    49.             if(uniqueID == 1)
    50.             {
    51.                 return KeyCode.Alpha1;
    52.             }
    53.             else if (uniqueID == 2)
    54.             {
    55.                 return KeyCode.Alpha2;
    56.             }
    57.             else if (uniqueID == 3)
    58.             {
    59.                 return KeyCode.Alpha3;
    60.             }
    61.             else
    62.             {
    63.                 Debug.Log("ERROR");
    64.                 return KeyCode.None;
    65.             }
    66.         }
    67.     }
    68. }
    69.  
     
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    bug 734257 filed on this.

    workaround - dont use the same name for your commands.
     
  5. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    Thanks.
     
  6. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    Since I can't use non-unique names (the functionality is built into the parent class... so all scripts will have the same names) I found another work-around.

    In case anybody has the same problem the work-around I did was to keep a list<> of all of the Feat child classes added to the GameObject. Instead of using [Command] CmdUseFeat() I call [Command] CmdUseFeat(byte index) with the index of the feat calling the action, then look up this feat on the list when the command is called.

    There might be other work-arounds as well.
     
  7. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    I'm still struggling with this bug as it doesn't allow UNET to work well with inheritance... which in OOP is just about every object! Seems like a major issue I'm surprised nobody else is having problems. Is there an ETA on the fix?
     
    RikuTheFuffs likes this.
  8. RikuTheFuffs

    RikuTheFuffs

    Joined:
    Sep 9, 2013
    Posts:
    10
    Just discovered this problem in my project too. I just spent the last 2 days reworking my characters' skilling system only to discover this problem. This is a very urgent issue to solve, and the craziest thing is that it isn't even prioritized on the issue tracker.
     
    Zullar likes this.
  9. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    621
    How do we get it prioritized on the issue tracker?
     
  10. RikuTheFuffs

    RikuTheFuffs

    Joined:
    Sep 9, 2013
    Posts:
    10
    There are votes you can put under the topic in the issue tracker, but in the ned it's up to Unity's dev team
     
    Zullar likes this.
unityunity