ArgumentException: Getting control 2's position in a group with only 2 controls when doing mouseDown

Hey,

I've created a script that enters a text string, created in another script, into a chat box window with scrollview.

I get the following error message, even though the program seems to work like it should:


ArgumentException: Getting control 2's position in a group with only 2 controls when doing mouseDown Aborting

UnityEngine.GUILayoutGroup.GetNext () UnityEngine.GUILayoutUtility.BeginLayoutGroup (UnityEngine.GUIStyle style, UnityEngine.GUILayoutOption[] options, System.Type LayoutType) [0x00000] UnityEngine.GUILayout.BeginHorizontal (UnityEngine.GUIStyle style, UnityEngine.GUILayoutOption[] options) [0x00000] UnityEngine.GUILayout.BeginHorizontal (UnityEngine.GUILayoutOption[] options) [0x00000] Chat.GlobalChatWindow (Int32 id) (at Assets\Example1\Chat.js:250) UnityEngine.GUI+_Window.Do () UnityEngine.GUI.BeginWindows (UnityEngine.Event e, Int32 skinMode, UnityEngine.IDList idlist, Int32 editorWindowInstanceID)


The only thing that does not work is that the scroll window does not automatically scroll down to show the last entry (but it does scroll to show the second-to-last entry).

I've used the M2H Networking Project, the companion project to the pdf "Unity networking; the Zero to Hero guide". In it, I've added my own RPC script:

@RPC
function RollCall(name : String, total : String, dice : String) {
    addGameChatMessage(name+" rolls "+total+", on "+dice);
}

The addGameChatMessage function, for reference:

    function addGameChatMessage(str : String){
        ApplyGlobalChatText("", str);
        if(Network.connections.length>0){
            networkView.RPC("ApplyGlobalChatText", RPCMode.Others, "", str);    
        }   
    }

The ApplyGlobalChatText function:

    @RPC
    function ApplyGlobalChatText (name : String, msg : String)
    {
        var entry = new ChatEntry();
        entry.name = name;
        entry.text = msg;

        chatEntries.Add(entry);

        //Remove old entries
        if (chatEntries.Count > 300){
            chatEntries.RemoveAt(0);
        }

        scrollPosition.y = 1000000; 
    }

The RollCall function is called inside the function of a window, called GlobalChatWindow. The script basically checks to see if anything is stored in MouseInformer.dList and if there is, this data is cleared and a chat message is generated. In my own script the MouseInformer.dList contents are gathered into strings and send to the RollCall function, but since this has nothing to do with the exception, I've removed the code responsible for that:

function GlobalChatWindow (id : int) {

    GUILayout.BeginVertical();
    GUILayout.Space(5);
    GUILayout.EndVertical();

    // Begin a scroll view. All rects are calculated automatically - 
    // it will use up any available screen space and make sure contents flow correctly.
    // This is kept small with the last two parameters to force scrollbars to appear.
    scrollPosition = GUILayout.BeginScrollView (scrollPosition);

    for (var entry : ChatEntry in chatEntries)
    {
        GUILayout.BeginHorizontal(); //UNITY SAYS THIS IS WHERE THE EXCEPTION ORIGINATES
        if(entry.name==""){//Game message
            GUILayout.Label (entry.text);
        }else{
            GUILayout.Label (entry.name+": "+entry.text);
        }
        GUILayout.EndHorizontal();
        GUILayout.Space(-5);

    }
    // End the scrollview we began above.
    GUILayout.EndScrollView ();

    var mouseInformer : MouseInformer = GetComponent("MouseInformer");
    if (checkWindow.Contains(Input.mousePosition) && Input.GetMouseButtonDown(0) && mouseInformer.dList.length > 0) {

        mouseInformer.ClearAll();
        //networkView.RPC("RollCall", RPCMode.All, playerName, outputTotal+"", diceTypeString);
        networkView.RPC("RollCall", RPCMode.All, playerName, "Result", "Many dice");

    }

    if (Event.current.type == EventType.keyDown && Event.current.character == "
" && inputField.Length > 0)
    {
        HitEnter(inputField);
    }
    GUI.SetNextControlName("Chat input field");
    inputField = GUILayout.TextField(inputField);
}

I believe the problem could be in your for loop over chatEntries. There are two passes to the OnGUI thread (they are called "events" in Unity), the layout event runs through and basically does roll call and layout planning on the GUI components and the repaint event draws the components to the screen. If the components change between these two GUI events, the layout manager gets confused and produces this message. The contents of your chat entries is externally controlled (from the OnGUI thread's perspective) and may be changing the contents of that collection between the events. This is forbidden.

Not absolutely sure that field is your problem but that's where I would start. That message is always produced in a circumstance like this. I have gotten around this before by creating a copy of the externally controlled collection in the layout pass (i.e., Event.current.type == EventType.Layout).