playMaker

Author Topic: How to add a new field to FsmArray.cs  (Read 610 times)

Fitbie

  • Playmaker Newbie
  • *
  • Posts: 31
How to add a new field to FsmArray.cs
« on: December 01, 2022, 05:18:33 AM »
Hi guys!
I use a third-party script for the save system (from the Pixel Crushers "Dialogue System")
This script finds all Playmaker global arrays and serializes them into Json (also using another script from the Dialogue system)
Code: [Select]
using System;
using System.Collections.Generic;
using UnityEngine;
using HutongGames.PlayMaker;

namespace PixelCrushers
{

    /// <summary>
    /// Saves a global FsmArray.
    /// </summary>
    [AddComponentMenu("Pixel Crushers/Third Party/PlayMaker Support/FsmArray Saver")]
    public class FsmArraySaver : Saver
    {

        public string fsmArrayName;
       
        [Serializable]
        public class Data
        {
            public List<bool> boolValues = new List<bool>();
            public List<int> intValues = new List<int>();
            public List<float> floatValues = new List<float>();
            public List<string> stringValues = new List<string>();
           
       
           
           
        }

        public override string RecordData()
        {
            var data = new Data();
            var fsmArray = FsmVariables.GlobalVariables.FindFsmArray(fsmArrayName);
            if (fsmArray == null) return string.Empty;
            if (fsmArray.boolValues != null) data.boolValues.AddRange(fsmArray.boolValues);
            if (fsmArray.intValues != null) data.intValues.AddRange(fsmArray.intValues);
            if (fsmArray.floatValues != null) data.floatValues.AddRange(fsmArray.floatValues);
            if (fsmArray.stringValues != null) data.stringValues.AddRange(fsmArray.stringValues);
           
           
            return SaveSystem.Serialize(data);
        }

        public override void ApplyData(string s)
        {
            var fsmArray = FsmVariables.GlobalVariables.FindFsmArray(fsmArrayName);
            if (fsmArray == null) return;
            if (string.IsNullOrEmpty(s)) return;
            var data = SaveSystem.Deserialize<Data>(s);
            if (data == null) return;
            fsmArray.boolValues = data.boolValues.ToArray();
            fsmArray.intValues = data.intValues.ToArray();
            fsmArray.floatValues = data.floatValues.ToArray();
            fsmArray.stringValues = data.stringValues.ToArray();
        }
    }
}

For my project I created a new class for the inventory (Scriptable Object with an Int object ID and Sprite with an image of the item) and named it "InvItem" and added it to Playmaker using Variable Type Definition





And I would like my InItem array to be serialized in the SaveSystem script as well. As far as I understand, to do that I need to add a line in the "FsmArray.cs" script, to make it look like this:
Code: [Select]
public class FsmArray : NamedVariable
    {
        public float[] floatValues;
        public int[] intValues;
        public bool[] boolValues;
        public string[] stringValues;
        public InvItem[] invItemValues;

So after that in the first SaveSystem script in RecordData() I can tell the script to check for InvItem arrays and save them.
But unfortunately FsmArray.cs is locked for editing.
Can you tell me if I'm doing it right, and if so, how can I change FsmArray.cs?

I'll be honest: I'm very bad at C# and most of the project I use PlayMaker in combination with simple C# scripts. So maybe I don't understand something (for example whether SaveSystem can serialize ScriptableObject). But I try to understand it.
Thanks :)

drown

  • Junior Playmaker
  • **
  • Posts: 58
Re: How to add a new field to FsmArray.cs
« Reply #1 on: December 08, 2022, 08:40:04 AM »
I think you have not gotten a reply because that seems to be a very specific issue to "Dialogue System". Playmaker is perfectly capable of handling custom variable types, even in arrays.

I recreated your problem using a different (the only one I have at hand) save system for playmaker : Easy Save 3. It also uses JSON so it should work similar to what you are using.

I then recreated everything you did : A new scriptable Object (invItem) that has and ID and a sprite Image. I then created a custom variable type from that. This loads fine in Playmaker.

I then created two sample objects and loaded them into an empty PM array of type invItem. Then i saved that to JSON using Easy Saves Playmaker integration. After that I loaded that JSON and used it to fill a new, independent array of type invItem in PM. Both arrays hold the same data, there are no errors saving or loading to or from JSON.

In conclusion that means : Something is off with the Dialogue Systems Save System. You should not need to edit any internal Playmaker Scripts to do what you just described.


Fitbie

  • Playmaker Newbie
  • *
  • Posts: 31
Re: How to add a new field to FsmArray.cs
« Reply #2 on: December 10, 2022, 05:01:43 AM »
Hi drown!
Thank you so much for the detailed response!
The problem is that I am using exactly the Dialog System, and I don't want to use Easy Save :D
Let me ask the question another way: in order to make it work I need to add these 3 lines of code:



As you can see, the editor gives an error because there is no invItemValues class in fsmarray. And apparently, to make it work - I need to write this in FsmArray.cs
But it is in readonly mode. That's why I want to know how I can add this line of code there.



EasySave seems to be able to save any custom classes, but in the Dialogue System I have to write it all myself.
Thanks :)

drown

  • Junior Playmaker
  • **
  • Posts: 58
Re: How to add a new field to FsmArray.cs
« Reply #3 on: December 11, 2022, 08:20:33 PM »
Hey,

I contacted the developer of Dialogue System because this bothered me. Very friendly support :) Glad to hear you were able to resolve it.

Do you mind sharing the solution with a bit of context incase anyone using Dialogue System and Playmaker stumbles upon the same problem ? That would be great!

Fitbie

  • Playmaker Newbie
  • *
  • Posts: 31
Re: How to add a new field to FsmArray.cs
« Reply #4 on: December 13, 2022, 05:16:43 AM »
Hi!
Sorry I didn't post sooner, I was busy
So, together with PixelCrushers we found a solution to this problem.
We decided to use loop and get every element of PlayMaker array as InvItem (my custom class for inventory items if you don't remember) and then include them into our data list


Code: [Select]
using System;
using System.Collections.Generic;
using UnityEngine;
using HutongGames.PlayMaker;

namespace PixelCrushers
{

    /// <summary>
    /// Saves a global FsmArray.
    /// </summary>
    [AddComponentMenu("Pixel Crushers/Third Party/PlayMaker Support/FsmArray Saver")]
    public class FsmArraySaver : Saver
    {

        public string fsmArrayName;
       
        [Serializable]
        public class Data
        {
           public List<InvItem> invItemValues = new List<InvItem>();         
        }

        public override string RecordData()
        {
            var data = new Data();
            var fsmArray = FsmVariables.GlobalVariables.FindFsmArray(fsmArrayName);
            if (fsmArray == null) return string.Empty;

            for (int i = 0; i < fsmArray.Length; i++)
            {   
                InvItem currentItemToRecord = fsmArray.Get(i) as InvItem;
                data.invItemValues.Add(currentItemToRecord);
            }
           
            return SaveSystem.Serialize(data);
        }

        public override void ApplyData(string s)
        {
            var fsmArray = FsmVariables.GlobalVariables.FindFsmArray(fsmArrayName);
            if (fsmArray == null) return;
            if (string.IsNullOrEmpty(s)) return;
            var data = SaveSystem.Deserialize<Data>(s);
            if (data == null) return;
            for (int i = 0; i < fsmArray.Length; i++)
            {
                InvItem currentItemToApply = data.invItemValues[i];
                fsmArray.Set(i, currentItemToApply);
            }
           
        }
    }
}

And yes, don't forget - your Scriptable Object must be [System.Serializable]

Also I modified the script further, since I have two inventories at the same time, if anyone is interested - I can send you :)