Exception with Async Load

slipyfrog

New member
Bug:
An ArgumentException occurs When BehaviorManager::EnableBehavior(Behavior) is called multiple times before the BehaviorTree has completed loading
ArgumentException: An item with the same key has already been added. Key: BT.AI.Default - Behavior
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <f646c7a159d243a7909d5204af0f0c56>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <f646c7a159d243a7909d5204af0f0c56>:0)
BehaviorDesigner.Runtime.BehaviorManager.LoadBehaviorComplete (BehaviorDesigner.Runtime.Behavior behavior, BehaviorDesigner.Runtime.BehaviorManager+BehaviorTree behaviorTree) (at Assets/External/Behavior Designer/Runtime/BehaviorManager.cs:525)
BehaviorDesigner.Runtime.BehaviorManager+<CheckThreadLoaders>d__78.MoveNext () (at Assets/External/Behavior Designer/Runtime/BehaviorManager.cs:381)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at /Users/bokken/build/output/unity/unity/Runtime/Export/Scripting/Coroutines.cs:17)
UnityEngine.GUIUtility:processEvent(Int32, IntPtr, Boolean&) (at /Users/bokken/build/output/unity/unity/Modules/IMGUI/GUIUtility.cs:190)

Steps
1. From the inspector for a BehaviorTree component, ensure that 'AsynchronousLoad' is checked and 'Star When Enabled' is false.
2. From the Awake of a component that is attached to the same game object, call 'm_BehaviorTree .EnableBehavior( )' twice.
3. Press play
Observed
Note that the exception occurs because the behavior is added to the activeThreads list of the BehaviorManager twice because

public class CreateBug : Monobehaviour
public BehaviorTree m_BehaviorTree;
void Awake(){
m_BehaviorTree = GetComponent<BehaviorTree>();
m_BehaviorTree .EnableBehavior( );
m_BehaviorTree .EnableBehavior( );
}
}

Inside the EnableBehavior then following does not trigger an early exit if EnableBehavior is called multiple times as the behavior is not enabled until LoadBehaviorComplete is called.
.
if (IsBehaviorEnabled(behavior)) {
return;



A simple guard will fix the issue:

Code:
[QUOTE]
from the BehaviorManager class:



public void EnableBehavior(Behavior behavior)
{
    BehaviorTree behaviorTree;
 
    //-- Added Start
    if ( behavior.waitingForLoadThread )
    {
        return;
    }
    //-- Added End
 
    if (IsBehaviorEnabled(behavior)) {. //this is not enough to ensure that EnableBehavior exits easy when aysncLoad is enabled
        return;
    }

   ...
   ...
   ...
    if (behavior.AsynchronousLoad) {
         ...
        ....
        ....
    //-- Added Start
        behavior.waitingForLoadThread = true;
    //-- Added End

        activeThreads.Add(loader);   //code will guard against behavior being added to activeThread multiple times
       ....
       ....
       .....
    } else {
        behaviorTree = LoadBehavior(behavior, behavior.gameObject, behavior.gameObject.name, behavior.transform);
        LoadBehaviorComplete(behavior, behaviorTree);
    }
}
[/QUOTE]
 
Top