Example #1
0
        /// <summary>
        /// Create state machine info for a given type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static StateMachineInfo Create(Type type, Type statesType)
        {
            var typeName = type.FullName;

            if (_cache.TryGetValue(typeName, out var info))
            {
                return(info);
            }

            var values = Enum.GetValues(statesType);
            var states = new StateInfo[values.Length];

            foreach (var value in values)
            {
                var index = (int)value;
                var name  = value.ToString();

                if (index < 0 || index >= states.Length)
                {
                    throw new UnityException("State enum must be sequential and start from zero");
                }

                states[index] = new StateInfo {
                    Name = value.ToString(), Mask = (1UL << index), Index = index
                };
            }

            // Create a new state machine info
            info                   = new StateMachineInfo();
            info.TargetType        = type;
            info.States            = states;
            info._transitionStride = states.Length + 1;
            _cache.Add(typeName, info);

            // Get state method and transitions
            info._transitions = new StateTransitionInfo[states.Length * info._transitionStride];
            foreach (var stateToInfo in states)
            {
                // State method?
                var stateMethod = type.GetMethod($"On{stateToInfo.Name}", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                if (null != stateMethod)
                {
                    var parameters = stateMethod.GetParameters();
                    if (parameters.Length == 0)
                    {
                        stateToInfo.InvokeDelegate = OpenDelegate.Create(stateMethod);
                    }
                    else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(float))
                    {
                        stateToInfo.InvokeWithTimeDelegate = OpenDelegate <float> .Create(stateMethod);
                    }
                    else
                    {
                        throw new UnityException($"method for state '{stateToInfo.Name}' does not match a valid state signature");
                    }
                }

                // Add the "Any" to state transition
                info._transitions[info.GetTransitionIndex(-1, stateToInfo.Index)] = CreateTransition(info, null, stateToInfo);

                // Add transition from all other states
                foreach (var stateFromInfo in states)
                {
                    info._transitions[info.GetTransitionIndex(stateFromInfo.Index, stateToInfo.Index)] =
                        CreateTransition(info, stateFromInfo, stateToInfo);
                }
            }

            return(info);
        }