playMaker

Author Topic: [SOLVED] FSM Template Creation via Code  (Read 3647 times)

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
[SOLVED] FSM Template Creation via Code
« on: September 25, 2018, 11:52:38 AM »
Hello!

I have been trying for awhile now to create an FSM Template Via code, and i have been failing miserably. I have been using this method:

Code: [Select]
public static void GenerateTemplate(Effect effect) {
var fsmTemplate = (FsmTemplate)CreateInstance(typeof(FsmTemplate));
fsmTemplate.Category = "HotspotEffect";

fsmTemplate.fsm = new Fsm {
DataVersion = Convert.ToInt32(DateTime.Today.ToString("ddMM")),
UsedInTemplate = fsmTemplate,
Name = effect.name.SnakeCaseToCapitalizedCase()
};

var startEvent = new FsmEvent("START " + effect.name.SnakeCaseToUpperCase());
var startTransition = new FsmTransition
{
FsmEvent = startEvent,
ToState = effect.name.SnakeCaseToCapitalizedCase()
};
var applyState = new FsmState(fsmTemplate.fsm)
{
Name = effect.name.SnakeCaseToCapitalizedCase(),
Position = new Rect(130, 60, 128, 30),
Transitions = new[]
{
new FsmTransition {
                    FsmEvent = FsmEvent.Finished,
                    ToState = "After " + effect.name.SnakeCaseToCapitalizedCase()
                }
}
};
var finishState = new FsmState(fsmTemplate.fsm)
{
Name = "After " + effect.name.SnakeCaseToCapitalizedCase(),
Position = new Rect(130, 120, 128, 15)
};
var finishAction = new FinishHotspotAction();
// Documentation says: "Called in the editor when an action is added to a state or reset". Not clear if via code is needed, apparently it does not generate errors.
//finishAction.Reset();
finishState.Actions = new FsmStateAction[] { finishAction };
finishState.SaveActions();

fsmTemplate.fsm.States = new[] { applyState, finishState };
fsmTemplate.fsm.Events = new[] { startEvent };
fsmTemplate.fsm.GlobalTransitions = new[] { startTransition };

AssetDatabase.CreateAsset(fsmTemplate, @"Assets\PlaymakerCustomTemplates\" + effect.name + ".asset");
AssetDatabase.SaveAssets();

effect.templateFSM = fsmTemplate;
}

The template is generated correctly, in the folder specified. Everything is working fine, however, when i try to move or add any state to the template, this happens:

Quote
NullReferenceException: Object reference not set to an instance of an object
HutongGames.PlayMakerEditor.FsmGraphView.UpdateGraphBounds (Vector2 viewPos, Single padding) (at .../PlayMaker/Editor/Classes/FsmGraphView.cs:337)

I believe this issue is here because i'm not creating templates the way Hutong Games intended (whichever way it is), so i come here to ask:
What is the right way to create and istantiate an FSM Template?

I do believe that i'm supposed to use the FSMBuilder class, however even when using that, i can't seem to get anywhere, as i don't know how to load an Fsm, or export one to a template. I've been fighting with this system for days, can anyone help?
« Last Edit: October 11, 2018, 03:56:38 AM by paradoxjester »

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #1 on: October 02, 2018, 03:25:56 AM »
Bump!

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #2 on: October 02, 2018, 03:29:02 AM »
Hi,

 uhm, I don't know about this, let me ping Alex.

 Bye,

 Jean

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #3 on: October 02, 2018, 03:34:04 AM »
Hi,

 ok, try this:

          var template = (FsmTemplate)ScriptableObject.CreateInstance(typeof(FsmTemplate));
         template.fsm = new Fsm();
            template.fsm.Reset(null);
           template.fsm.UsedInTemplate = template;

Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #4 on: October 03, 2018, 03:54:50 AM »
Hello,

I've tried using the provided code, however the same error seems to happen. As soon as i click on a state or try to move anything in the template, that error appears in the console, and the state i'm trying to move sticks to my cursor, and i can't remove it.  :'(

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #5 on: October 04, 2018, 03:26:12 AM »
Hi,

 ok, maybe it's in the definition itself of the states and transition that something is wrong.

Let me have a go at this.

 Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #6 on: October 04, 2018, 06:56:41 AM »
Thanks alot!
I'll be waiting for your tests, and check out some more things on my own :)

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #7 on: October 05, 2018, 02:37:43 AM »
Hi,

 ok, turns out that you are setting the .DataVersion of the fsmTemplate.fsm, and that's not the Date, but an internal version indicator for how to deserialize data.

 Don't set that property and all is well.

 Can you confirm on your end? It works here.

 Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #8 on: October 05, 2018, 04:01:18 AM »
Hello!

Unfortunately that didn't do it for us :(
I'm gonna paste what my generation code looks like:

Code: [Select]
public static void GenerateTemplate(Effect effect) {
var fsmTemplate = (FsmTemplate)CreateInstance(typeof(FsmTemplate));

fsmTemplate.Category = "HotspotEffect";

fsmTemplate.fsm = new Fsm();
fsmTemplate.fsm.Reset(null);

var startEvent = new FsmEvent("START " + effect.name.SnakeCaseToUpperCase());
var startTransition = new FsmTransition
{
FsmEvent = startEvent,
ToState = effect.name.SnakeCaseToCapitalizedCase()
};
var applyState = new FsmState(fsmTemplate.fsm)
{
Name = effect.name.SnakeCaseToCapitalizedCase(),
Position = new Rect(130, 60, 128, 30),
Transitions = new[]
{
new FsmTransition {
FsmEvent = FsmEvent.Finished,
ToState = "After " + effect.name.SnakeCaseToCapitalizedCase()
}
}
};
var finishState = new FsmState(fsmTemplate.fsm)
{
Name = "After " + effect.name.SnakeCaseToCapitalizedCase(),
Position = new Rect(130, 120, 128, 15)
};
var finishAction = new FinishHotspotAction();
// Documentation says: "Called in the editor when an action is added to a state or reset". Not clear if via code is needed, apparently it does not generate errors.
//finishAction.Reset();
finishState.Actions = new FsmStateAction[] { finishAction };
finishState.SaveActions();

fsmTemplate.fsm.States = new[] { applyState, finishState };
fsmTemplate.fsm.Events = new[] { startEvent };
fsmTemplate.fsm.GlobalTransitions = new[] { startTransition };
fsmTemplate.fsm.Name = effect.name.SnakeCaseToCapitalizedCase();
fsmTemplate.fsm.UsedInTemplate = fsmTemplate;

AssetDatabase.CreateAsset(fsmTemplate, @"Assets\PlaymakerCustomTemplates\" + effect.name + ".asset");
AssetDatabase.SaveAssets();

effect.templateFSM = fsmTemplate;
}

Again, the issue isn't on the generation, it's on manipulating the generated template afterwards. When i try to move any state around, the pointer gets stuck on that state, and i start getting alot of errors in the console  :(

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #9 on: October 08, 2018, 03:35:51 AM »
Hi,

 ok, so you'll need to create a script with no dependancy to other part of your code, so that I replicate locally.

 Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #10 on: October 08, 2018, 04:23:47 AM »
Hello!

Sure, here it is:

Code: [Select]
public static void GenerateTemplate(string effectName) {
var fsmTemplate = (FsmTemplate)CreateInstance(typeof(FsmTemplate));

fsmTemplate.Category = "HotspotEffect";

fsmTemplate.fsm = new Fsm();
fsmTemplate.fsm.Reset(null);

var startEvent = new FsmEvent("START " + effectName);
var startTransition = new FsmTransition
{
FsmEvent = startEvent,
ToState = effectName
};
var applyState = new FsmState(fsmTemplate.fsm)
{
Name = effectName,
Position = new Rect(130, 60, 128, 30),
Transitions = new[]
{
new FsmTransition {
FsmEvent = FsmEvent.Finished,
ToState = "After " + effectName
}
}
};
var finishState = new FsmState(fsmTemplate.fsm)
{
Name = "After " + effectName,
Position = new Rect(130, 120, 128, 15)
};
var finishAction = new DebugLog();
finishState.Actions = new FsmStateAction[] { finishAction };
finishState.SaveActions();
fsmTemplate.fsm.States = new[] { applyState, finishState };
fsmTemplate.fsm.Events = new[] { startEvent };
fsmTemplate.fsm.GlobalTransitions = new[] { startTransition };
fsmTemplate.fsm.Name = effectName;
fsmTemplate.fsm.UsedInTemplate = fsmTemplate;

AssetDatabase.CreateAsset(fsmTemplate, @"Assets\Data\PlaymakerCustomTemplates\" + effectName + ".asset");
AssetDatabase.SaveAssets();
}

I used a string instead of my class, and switched out my custom action for the DebugLog() action, included in Playmaker. The issue still appears. The function is static because i run it via a button in the editor, using my custom editor script, but it should also work if you call it non-statically, so feel free to remove that. Also feel free to change the path at which i save the created Template.

Thank you very much!

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #11 on: October 09, 2018, 03:28:17 AM »
Hi,

 ok, All was because it was missing a start state, if you add your new states as opposed to overwrite the state list, it's all good.


Code: [Select]
    [MenuItem("PlayMaker/Test/Generate FsmTemplate bad")]
    public static void GenerateTemplateBad()
    {
        string effectName = "testBad";

        var fsmTemplate = (FsmTemplate)CreateInstance(typeof(FsmTemplate));

        fsmTemplate.Category = "HotspotEffect";

        fsmTemplate.fsm = new Fsm();
        fsmTemplate.fsm.Reset(null);

        var startEvent = new FsmEvent("START "+ effectName);
        var startTransition = new FsmTransition
        {
            FsmEvent = startEvent,
            ToState = effectName
        };
        var applyState = new FsmState(fsmTemplate.fsm)
        {
            Name = effectName,
            Position = new Rect(130, 60, 128, 16),
            Transitions = new[]
            {
            new FsmTransition {
                FsmEvent = FsmEvent.Finished,
                ToState = "After " + effectName
            }
        }
        };
        var finishState = new FsmState(fsmTemplate.fsm)
        {
            Name = "After " + effectName,
            Position = new Rect(130, 120, 128, 16)
        };
        var finishAction = new DebugLog();
        finishState.Actions = new FsmStateAction[] { finishAction };
        finishState.SaveActions();

        FsmState[] _states = fsmTemplate.fsm.States;
        ArrayUtility.Add(ref _states, finishState);
        ArrayUtility.Add(ref _states, applyState);
        fsmTemplate.fsm.States = _states;

        fsmTemplate.fsm.Events = new[] { startEvent };
        fsmTemplate.fsm.GlobalTransitions = new[] { startTransition };
        fsmTemplate.fsm.Name = effectName;
        fsmTemplate.fsm.UsedInTemplate = fsmTemplate;


        AssetDatabase.CreateAsset(fsmTemplate, @"Assets\Playmaker Custom Templates\test\" + effectName + ".asset");
        AssetDatabase.SaveAssets();
    }

Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #12 on: October 09, 2018, 04:29:34 AM »
Hello!

Thank you, if i add a start state then everything works fine!
Unfortunately, our generated templates would be cleaner without a start state...
I thought it was possible to copy states and save them into a template without a start state! Is it not?
Let me know if this is a possibility!

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: FSM Template Creation via Code
« Reply #13 on: October 10, 2018, 06:30:29 AM »
Hi,

 no, a Start state is mandatory, leave it empty, I usually even set the start state name to an empty string, so that it's clear it does nothing.

the mandatory start state comes from the FSM "Rule", a finite state machine must be in a state at all time, so no start state breaks the definition of finite state machine.


 Bye,

 Jean

paradoxjester

  • Playmaker Newbie
  • *
  • Posts: 12
Re: FSM Template Creation via Code
« Reply #14 on: October 11, 2018, 03:56:15 AM »
Hello!

Thank you so much for the wonderful help! We've worked around the start state issue, and now everything works with the rest of the project.

Thank you so much!