// Initialize state machine of one layer.
        private static bool InitLayerNodes(MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition,
            MyAnimationController animationController, string currentNodeNamePrefix, MyAnimationVirtualNodes virtualNodes, bool forceReloadMwm)
        {
            var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName);
            if (objBuilderStateMachine == null)
            {
                Debug.Fail("Animation state machine " + stateMachineName + " was not found.");
                return false;
            }

            bool result = true;
            // 1st step: generate nodes
            if (objBuilderStateMachine.Nodes != null)
            foreach (var objBuilderNode in objBuilderStateMachine.Nodes)
            {
                string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name;
                if (objBuilderNode.StateMachineName != null)
                {
                    // embedded state machine, copy its nodes
                    if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/", virtualNodes, forceReloadMwm))
                        result = false;
                }
                else
                {
                    var smNode = new VRageRender.Animations.MyAnimationStateMachineNode(absoluteNodeName);
                    if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.PassThrough
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                    {
                        smNode.PassThrough = true;
                    }
                    else
                    {
                        smNode.PassThrough = false;
                    }

                    if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any
                        || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                    {
                        virtualNodes.NodesAny.Add(absoluteNodeName, new MyAnimationVirtualNodeData()
                        {
                            AnyNodePrefix = currentNodeNamePrefix,
                            ExceptTarget = (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget)
                        });
                    }

                    layer.AddNode(smNode);

                    if (objBuilderNode.AnimationTree != null)
                    {
                        var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child, forceReloadMwm);
                        smNode.RootAnimationNode = smNodeAnimTree;
                    }
                    else
                    {
                        smNode.RootAnimationNode = new MyAnimationTreeNodeDummy();
                    }
                }
            }

            // 2nd step: generate transitions
            if (objBuilderStateMachine.Transitions != null)
            foreach (var objBuilderTransition in objBuilderStateMachine.Transitions)
            {
                string absoluteNameNodeFrom = currentNodeNamePrefix + objBuilderTransition.From;
                string absoluteNameNodeTo = currentNodeNamePrefix + objBuilderTransition.To;

                MyAnimationVirtualNodeData virtualNodeData;
                if (virtualNodes.NodesAny.TryGetValue(absoluteNameNodeFrom, out virtualNodeData))
                {
                    // nodes of type "any":
                    // "any" node is source: we create transitions directly from all nodes
                    // "any" node is target: we will use "any" node as pass through
                    foreach (var nodeFromCandidate in layer.AllNodes)
                    {
                        if (nodeFromCandidate.Key.StartsWith(virtualNodeData.AnyNodePrefix) // select nodes in the same SM
                            && nodeFromCandidate.Key != absoluteNameNodeFrom)    // disallow from "any" to the same "any"
                        {
                            // create transition if target is different from source or when we don't care about it
                            if (!virtualNodeData.ExceptTarget || absoluteNameNodeTo != nodeFromCandidate.Key)
                                CreateTransition(layer, animationController, nodeFromCandidate.Key, absoluteNameNodeTo, objBuilderTransition);
                        }
                    }
                }

                CreateTransition(layer, animationController, absoluteNameNodeFrom, absoluteNameNodeTo, objBuilderTransition);
            }

            return result;
        }
 private static void CreateTransition(MyAnimationStateMachine layer, MyAnimationController animationController,
     string absoluteNameNodeFrom, string absoluteNameNodeTo, MyObjectBuilder_AnimationSMTransition objBuilderTransition)
 {
     int conditionConjunctionIndex = 0;
     do
     {
         // generate transition for each condition conjunction
         var transition = layer.AddTransition(absoluteNameNodeFrom, absoluteNameNodeTo,
             new VRageRender.Animations.MyAnimationStateMachineTransition()) as
             VRageRender.Animations.MyAnimationStateMachineTransition;
         // if ok, fill in conditions
         if (transition != null)
         {
             transition.Name =
                 MyStringId.GetOrCompute(objBuilderTransition.Name != null ? objBuilderTransition.Name.ToLower() : null);
             transition.TransitionTimeInSec = objBuilderTransition.TimeInSec;
             transition.Sync = objBuilderTransition.Sync;
             transition.Priority = objBuilderTransition.Priority;
             if (objBuilderTransition.Conditions != null &&
                 objBuilderTransition.Conditions[conditionConjunctionIndex] != null)
             {
                 var conjunctionOfConditions =
                     objBuilderTransition.Conditions[conditionConjunctionIndex].Conditions;
                 foreach (var objBuilderCondition in conjunctionOfConditions)
                 {
                     var condition = ParseOneCondition(animationController, objBuilderCondition);
                     if (condition != null)
                         transition.Conditions.Add(condition);
                 }
             }
         }
         conditionConjunctionIndex++;
     } while (objBuilderTransition.Conditions != null &&
              conditionConjunctionIndex < objBuilderTransition.Conditions.Length);
 }
        // Convert one condition from object builder to in-game representation.
        private static MyCondition<float> ParseOneCondition(MyAnimationController animationController,
            MyObjectBuilder_AnimationSMCondition objBuilderCondition)
        {
            MyCondition<float> condition;

            objBuilderCondition.ValueLeft = objBuilderCondition.ValueLeft != null ? objBuilderCondition.ValueLeft.ToLower() : "0";
            objBuilderCondition.ValueRight = objBuilderCondition.ValueRight != null ? objBuilderCondition.ValueRight.ToLower() : "0";
            double lhs, rhs;
            if (Double.TryParse(objBuilderCondition.ValueLeft, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lhs))
            {
                if (Double.TryParse(objBuilderCondition.ValueRight, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out rhs))
                {
                    condition =
                        new VRage.Generics.StateMachine.MyCondition<float>(
                            animationController.Variables,
                            ConvertOperation(objBuilderCondition.Operation), (float) lhs,
                            (float) rhs);
                }
                else
                {
                    condition =
                        new VRage.Generics.StateMachine.MyCondition<float>(
                            animationController.Variables,
                            ConvertOperation(objBuilderCondition.Operation), (float) lhs,
                            objBuilderCondition.ValueRight);
                }
            }
            else
            {
                if (Double.TryParse(objBuilderCondition.ValueRight, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out rhs))
                {
                    condition =
                        new VRage.Generics.StateMachine.MyCondition<float>(
                            animationController.Variables,
                            ConvertOperation(objBuilderCondition.Operation),
                            objBuilderCondition.ValueLeft, (float) rhs);
                }
                else
                {
                    condition =
                        new VRage.Generics.StateMachine.MyCondition<float>(
                            animationController.Variables,
                            ConvertOperation(objBuilderCondition.Operation),
                            objBuilderCondition.ValueLeft, objBuilderCondition.ValueRight);
                }
            }
            return condition;
        }
        private void LiveDebugging_SendAnimationStateChangesToEditor(MyAnimationController animController)
        {
            if (animController == null)
                return;

            int layerCount = animController.GetLayerCount();
            if (layerCount != m_debuggingAnimControllerCurrentNodes.Count)
            {
                m_debuggingAnimControllerCurrentNodes.Clear();
                for (int i = 0; i < layerCount; i++)
                    m_debuggingAnimControllerCurrentNodes.Add(null);

                m_debuggingAnimControllerTreePath.Clear();
                for (int i = 0; i < layerCount; i++)
                {
                    m_debuggingAnimControllerTreePath.Add(new int[animController.GetLayerByIndex(i).VisitedTreeNodesPath.Length]);
                }
            }

            for (int i = 0; i < layerCount; i++)
            {
                var layerVisitedTreeNodesPath = animController.GetLayerByIndex(i).VisitedTreeNodesPath;
                if (animController.GetLayerByIndex(i).CurrentNode != m_debuggingAnimControllerCurrentNodes[i]
                    || !LiveDebugging_CompareAnimTreePathSeqs(layerVisitedTreeNodesPath, m_debuggingAnimControllerTreePath[i]))
                {
                    Array.Copy(layerVisitedTreeNodesPath, m_debuggingAnimControllerTreePath[i], layerVisitedTreeNodesPath.Length); // local copy
                    m_debuggingAnimControllerCurrentNodes[i] = animController.GetLayerByIndex(i).CurrentNode;
                    if (m_debuggingAnimControllerCurrentNodes[i] != null)
                    {
                        var msg =
                            MyExternalDebugStructures.ACSendStateToEditorMsg.Create(m_debuggingAnimControllerCurrentNodes[i].Name, m_debuggingAnimControllerTreePath[i]);
                        MySessionComponentExtDebug.Static.SendMessageToClients(msg);
                    }
                }
            }
        }