private void GetPrefabData(PlayMakerFSM fsm, FsmModel model)
        {
            if (PrefabUtility.GetPrefabType(fsm.gameObject) != PrefabType.Prefab)
            {
                return;
            }

            model.fromPrefab = AssetDatabase.GetAssetPath(fsm.gameObject);
            model.prefabGuid = AssetDatabase.AssetPathToGUID(model.fromPrefab);
        }
示例#2
0
        protected FsmModel <TState, TEvent> DeserializeModel(object args)
        {
            var jsonModel = JsonConvert.DeserializeObject <JsonFsmModel>(_json);

            var model = new FsmModel <TState, TEvent>();

            if (jsonModel.Start != null)
            {
                model.Start = CSharpEval.Execute <TState>(jsonModel.Start, args, _refs);
            }

            if (jsonModel.OnJump != null)
            {
                model.OnJump = x => CSharpEval.Execute(jsonModel.OnJump, _concatArgs(args, new { _args = x }), _refs);
            }

            if (jsonModel.OnReset != null)
            {
                model.OnReset = x => CSharpEval.Execute(jsonModel.OnReset, _concatArgs(args, new { _args = x }), _refs);
            }

            if (jsonModel.OnTrigger != null)
            {
                model.OnTrigger = x => CSharpEval.Execute(jsonModel.OnTrigger, _concatArgs(args, new { _args = x }), _refs);
            }

            if (jsonModel.OnFire != null)
            {
                model.OnFire = x => CSharpEval.Execute(jsonModel.OnFire, _concatArgs(args, new { _args = x }), _refs);
            }

            if (jsonModel.OnError != null)
            {
                model.OnError = x => CSharpEval.Execute(jsonModel.OnError, _concatArgs(args, new { _args = x }), _refs);
            }

            if (jsonModel.States != null)
            {
                foreach (var sKvp in jsonModel.States)
                {
                    var sModel = new FsmStateModel <TState, TEvent>();

                    if (sKvp.Value.Enable != null)
                    {
                        sModel.Enable = x => CSharpEval.Execute <bool>(sKvp.Value.Enable, _concatArgs(args, new { _args = x }), _refs);
                    }

                    if (sKvp.Value.OnEnter != null)
                    {
                        sModel.OnEnter = x => CSharpEval.Execute(sKvp.Value.OnEnter, _concatArgs(args, new { _args = x }), _refs);
                    }

                    if (sKvp.Value.OnExit != null)
                    {
                        sModel.OnExit = x => CSharpEval.Execute(sKvp.Value.OnExit, _concatArgs(args, new { _args = x }), _refs);
                    }

                    if (sKvp.Value.Events != null)
                    {
                        foreach (var eKvp in sKvp.Value.Events)
                        {
                            var eModel = new FsmEventModel <TState, TEvent>();

                            if (eKvp.Value.Enable != null)
                            {
                                eModel.Enable = x => CSharpEval.Execute <bool>(eKvp.Value.Enable, _concatArgs(args, new { _args = x }), _refs);
                            }

                            if (eKvp.Value.Execute != null)
                            {
                                eModel.Execute = x => CSharpEval.Execute <object>(eKvp.Value.Execute, _concatArgs(args, new { _args = x }), _refs);
                            }

                            if (eKvp.Value.JumpTo != null)
                            {
                                eModel.JumpTo = x => CSharpEval.Execute <TState>(eKvp.Value.JumpTo, _concatArgs(args, new { _args = x }), _refs);
                            }

                            sModel.Events.Add(_convertTo <TEvent>(eKvp.Key), eModel);
                        }
                    }

                    model.States.Add(_convertTo <TState>(sKvp.Key), sModel);
                }
            }

            return(model);
        }
        public FsmModel CreateModel(PlayMakerFSM fsm)
        {
            var model = new FsmModel {
                description = fsm.FsmDescription,
                states      = new List <FsmStateModel>(),
            };

            GetPrefabData(fsm, model);

            // Pre-populate state models.
            var stateLookup = new Dictionary <string, FsmStateModel>();

            foreach (var state in fsm.FsmStates)
            {
                // Cannot support duplicate state names, and PlayMaker's GUI does not allow this but gotta check.
                if (stateLookup.ContainsKey(state.Name))
                {
                    throw new System.Exception("Duplicate state name: " + state.Name);
                }

                if (state.Name.Contains("\""))
                {
                    throw new System.Exception("Illegal characters in state name '" + state.Name + "'");
                }

                var stateModel = new FsmStateModel {
                    name        = state.Name,
                    transitions = new List <FsmTransitionModel>(),
                    isStart     = fsm.Fsm.StartState == state.Name,
                };

                model.states.Add(stateModel);

                stateLookup[state.Name] = stateModel;
            }

            // All events
            var fsmEvents = new HashSet <string>(fsm.FsmEvents.Select(e => e.Name));

            // Now populate transitions
            foreach (var state in fsm.FsmStates)
            {
                var stateModel = stateLookup[state.Name];

                // Gather transition events
                var evts = new HashSet <string>();
                foreach (var transition in state.Transitions)
                {
                    if (evts.Contains(transition.FsmEvent.Name))
                    {
                        throw new System.Exception("Duplicate transition event: " + transition.FsmEvent.Name + " in state: " + state.Name);
                    }

                    FsmStateModel toState;
                    if (!stateLookup.TryGetValue(transition.ToState, out toState))
                    {
                        throw new System.Exception("Missing to state in transition: " + transition.FsmEvent.Name + " in state: " + state.Name);
                    }

                    if (toState == stateModel)
                    {
                        throw new System.Exception("Detected self transition in state: " + state.Name + " for event: " + transition.FsmEvent.Name);
                    }

                    evts.Add(transition.FsmEvent.Name);
                }

                // Gather internal actions
                stateModel.internalActions = new List <FsmInternalActionModel>();
                foreach (var action in state.Actions)
                {
                    if (action is Actions.InternalAction)
                    {
                        var i = action as Actions.InternalAction;
                        if (i._event == null || string.IsNullOrEmpty(i._event.Value))
                        {
                            throw new System.Exception(string.Format("Internal action in '{0}' has no event defined", state.Name));
                        }
                        else if (!fsmEvents.Contains(i._event.Value))
                        {
                            throw new System.Exception(string.Format("Internal action in '{0}' has event '{1}' but no event by that name is defined", state.Name, i._event.Value));
                        }

                        var actionModel = new FsmInternalActionModel {
                            evt = new FsmEventModel {
                                name = i._event.Value,
                            },
                            _delegate = new FsmDelegateMethod(),
                        };

                        FillInMethodInfo(stateModel, action as Actions.BaseDelegateAction, i._event.Value + " (internal action)", actionModel._delegate);

                        stateModel.internalActions.Add(actionModel);
                    }
                }

                // Gather transitions
                foreach (var transition in state.Transitions)
                {
                    FsmStateModel toState = stateLookup[transition.ToState];

                    var transitionModel = new FsmTransitionModel {
                        evt = new FsmEventModel {
                            name = transition.FsmEvent.Name,
                        },
                        from = stateModel,
                        to   = toState,
                    };

                    stateModel.transitions.Add(transitionModel);
                }

                // Gather on enter/exit
                stateModel.onEnter = new List <FsmOnEnterExitModel>();
                stateModel.onExit  = new List <FsmOnEnterExitModel>();

                foreach (var action in state.Actions)
                {
                    AddEnterExitEvent(action as Actions.BaseDelegateAction, stateModel);
                }

                // Gather ignore events
                var toIgnore = new HashSet <string>();
                stateModel.ignoreEvents = new List <FsmEventModel>();
                foreach (var action in state.Actions)
                {
                    var ignore = action as Actions.IgnoreEventAction;
                    if (ignore == null || ignore._event == null || string.IsNullOrEmpty(ignore._event.Value) || toIgnore.Contains(ignore._event.Value))
                    {
                        continue;
                    }

                    // Sanity check, this event should not be used in a transition or an internal action
                    var evt = ignore._event.Value;
                    foreach (var internalAction in stateModel.internalActions)
                    {
                        if (internalAction.evt.name == evt)
                        {
                            throw new System.Exception(string.Format("Ignore action event in '{0}' has event '{1}' that is used by an internal action", state.Name, evt));
                        }
                    }
                    foreach (var transition in stateModel.transitions)
                    {
                        if (transition.evt.name == evt)
                        {
                            throw new System.Exception(string.Format("Ignore action event in '{0}' has event '{1}' that is used by a transition", state.Name, evt));
                        }
                    }

                    stateModel.ignoreEvents.Add(new FsmEventModel {
                        name = ignore._event.Value
                    });
                }
            }

            // Now gather all required interfaces
            var interfaces = new HashSet <Type>();

            foreach (var state in model.states)
            {
                foreach (var m in state.onEnter)
                {
                    interfaces.Add(m._delegate._interface);
                }
                foreach (var m in state.internalActions)
                {
                    interfaces.Add(m._delegate._interface);
                }
                foreach (var m in state.onExit)
                {
                    interfaces.Add(m._delegate._interface);
                }
            }

            model.context = new FsmContextModel {
                requiredInterfaces = interfaces.OrderBy(t => t.FullName).ToList(),
            };

            // Gather all used events
            var events = new HashSet <string>();

            foreach (var state in model.states)
            {
                foreach (var transition in state.transitions)
                {
                    events.Add(transition.evt.name);
                }
                foreach (var action in state.internalActions)
                {
                    events.Add(action.evt.name);
                }
            }

            model.events = events.OrderBy(e => e).Select(e => new FsmEventModel {
                name = e
            }).ToList();

            return(model);
        }