Ok, the below action will add a FSM Template at runtime.
It'll also optionally check if the FSM Template should be unique or not. If it's Unique then it's a unique instance and won't bother checking if an instance of the same FSM Template already exists. If it's not unique then it'll check if the FSM name (if supplied) exists or the FSM template exists. If either of them do exist when it's not unique then it won't add the FSM template.
You can optionally set the FSM to be enabled or disabled on creation so you can optionally enable it later as needed.
Last but not least you can optionally send variables to the newly added template. This will initially disable the FSM, add the template, change the variables, then enable the FSM so it can properly start with the variables added.
using System.Collections.Generic;
using UnityEngine;
namespace HutongGames.PlayMaker.Actions {
[ActionCategory(ActionCategory.StateMachine)]
public class AddFsmTemplate : FsmStateAction {
[RequiredField]
public FsmOwnerDefault gameObject;
[RequiredField]
public FsmTemplate template;
public FsmString name;
public FsmBool active;
public FsmBool unique;
[CompoundArray("Variables", "Name", "Variable")]
[RequiredField]
public FsmString[] variableNames;
[RequiredField]
public FsmVar[] variables;
private GameObject previousGo;
private List<PlayMakerFSM> fsms;
public override void Reset() {
gameObject = null;
template = null;
name = new FsmString { UseVariable = true };
active = new FsmBool { Value = true };
unique = new FsmBool { Value = false };
variableNames = new FsmString[0];
variables = new FsmVar[0];
}
public override void OnEnter() {
var go = Fsm.GetOwnerDefaultTarget( gameObject );
if ( go == null ) {
return;
}
bool exists = false;
if ( ! unique.Value ) {
if ( go != previousGo ) {
fsms = new List<PlayMakerFSM>();
fsms.AddRange( go.GetComponents<PlayMakerFSM>() );
previousGo = go;
}
if ( fsms.Count > 0 ) foreach ( PlayMakerFSM fsm in fsms ) {
if ( ( ( name.Value != "" ) && ( fsm.FsmName == name.Value ) ) || ( ( fsm.FsmTemplate != null ) && ( fsm.FsmTemplate.name == template.name ) ) ) {
exists = true;
}
}
}
if ( ! exists ) {
PlayMakerFSM newFsm = go.AddComponent<PlayMakerFSM>();
if ( name.Value != "" ) {
newFsm.FsmName = name.Value;
}
if ( ( ! active.Value ) || ( variableNames.Length > 0 ) ) {
newFsm.enabled = false;
}
newFsm.SetFsmTemplate( template );
if ( variableNames.Length > 0 ) {
if ( variableNames.Length > 0 ) for ( int i = 0; i < variableNames.Length; i++ ) {
if ( ! variableNames[i].IsNone ) {
NamedVariable target = newFsm.Fsm.Variables.GetVariable( variableNames[i].Value );
if ( target != null ) {
variables[i].ApplyValueTo( target );
}
}
}
if ( active.Value && ( ! newFsm.enabled ) ) {
newFsm.enabled = true;
}
}
if ( ! unique.Value ) {
fsms.Add( newFsm );
}
}
Finish();
}
}
}
Now all that's left is a "DestroyFSM" action to completely get rid of the FSM component. I have yet to figure this one out yet, but once I do this can be used very effectively for spell debuffs, temporary affects like drag on a rigidbody to simulate "slowing", and much much more.
Regarding performance using the above I saw very little loss, if any at all, so it seams perfectly safe to use as needed.