/// <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); }