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