Search Unity

[Updated] Cross Platform Easy Save - The Ultimate Serialization Plugin

Discussion in 'Assets and Asset Store' started by Voxel-Busters, Oct 22, 2018.

  1. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Cross Platform Easy Save plugin is an extremely easy to use and insanely powerful serialization plugin specially made for Unity. It can save and load both c# objects as well as Unity objects.

    Important Links
    Official Forum | Asset Store Page | Documentation | Tutorials | Videos | Support

    Highlights
    • Extremely easy to use. It takes 2 API's to get your job done!
    • Its powerful, super efficient, consumes less memory.
    • Supports properties.
    • Supports polymorphism.
    • Supports interfaces.
    • Supports cyclic references.
    • Supports multidimensional and jagged arrays.
    • Supports generic types (Dictionary, List etc).
    • Supports Unity types.
    • Supports runtime object serialization.
    • Supports scene object serialization.
    • Supports resource object serialization based on guid.
    • Supports saving to PlayerPrefs or as Files.
    • Supports batching save calls.
    • Source code is included.
    Well documented with video tutorials.

    Performance
    Performance is one of the key aspects used to determine the quality of the product. So this is one of main areas where we concentrated right from the beginning. And as per our test results, we recorded a performance gain of about 40-50% for serialization and 20-30% for deserialization tasks, when compared to c#'s Binary Formatter.

    Compatiblity
    • Fully compatible with almost all major development platforms including AOT and IL2CPP platforms such as iOS, WebGL, WSA and consoles.
    • Works with Unity Personal, Plus and Pro. Unity 2017.1 or newer is required.

    Get it now @ Early-Bird Price

    Setup


    Basic Save


    Scene Object Save


    Custom Object Save


    Batch Save Calls


    Support
    Feel free to post your questions, suggestions and feedback. And you can also contact us at support@voxelbusters.com or via Skype.
     
    Last edited: Oct 22, 2018
  2. hasanbayat

    hasanbayat

    Joined:
    Oct 18, 2016
    Posts:
    630
    Looks like a great library, keep it up!
     
    chaseholton and Voxel-Busters like this.
  3. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Thanks for updating @chaseholton

    Please post here for further questions.

    Cheers,
    VB Team
     
    chaseholton likes this.
  4. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Oh thanks dude! I do have another question. I'm trying to serialize a list of game objects but I'm getting an error, I attached it below.

    What I'm doing is OnDisable() on my GameManager script, I'm serializing a public list of GameObjects so that when the game opens again, OnEnable() Deserializes that list so that the player's inventory / bank is saved upon closing and loaded upon opening the game.

    Am I missing something super basic? lol I feel like going through the tutorial videos and documentation this should be okay, but I am so new to serialization that I am likely messing up somewhere obvious.

    Code (CSharp):
    1. public List<GameObject> bankedGO;
    2.  
    3. void OnDisable ()
    4. {
    5. SerializationManager.Serialize("bankedObjects", bankedGO);
    6. }
    7.  
    8. void OnEnable ()
    9. {
    10. bankedGO = SerializationManager.Deserialize<List<GameObject>>("bankedObjects");
    11. }
     

    Attached Files:

  5. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Plugin calls shared with us are perfect! It should do its job. Please make sure you have added your scene in BuildSettings. Rest should be taken care by the plugin. For more info, please watch this video tutorial on scene object serialization.

    Couple of pointers:
    1) Placement of save and load calls within OnEnable and OnDisable methods might not be ideal. Generally speaking serialization is an expensive operation, it should be invoked only when its required. For eg: save changes when you reach a checkpoint and reload data when you want to restart from last saved checkpoint.
    2) Save properties which are essential or likely to be modified. Let's say you have a static GameObject with a custom MonoBehaviour script and properties from this script are only getting changed at runtime. At this point, it's advisable to save MonoBehaviour only instead of whole GameObject.

    I guess, Spider-Man's phrase - With great power comes great responsibility holds good here :)
     
  6. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Hmmm I'm stumped. I feel like serialization and deserialization are just throwing those errors every time. I've tried just a single object instead of a List, always that same error... "found inconsistency at object level".
     
  7. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Sorry for the inconvenience caused. Do you see same problem with our demo scene?

    Anyways please send us DM with sample project having this issue. We will look into it. And also share Unity Editor version details in which this issue was noticed.
     
    Duffer123 likes this.
  8. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Yeah for some reason the scene loading example scene, after Creating Game Objects, serializing, closing and reopening and Deserializing, it's saying

    "
    [Serialization] The requested operation could not be completed. Please check error description for more details. Error description: Couldn't find parse function for token Invalid
    UnityEngine.Debug:LogError(Object)
    VoxelBusters.Serialization.SerializationManager:Deserialize(String, List`1) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/SerializationManager.cs:706)
    VoxelBusters.Serialization.Demo.PrimitiveGenerator:Deserialize() (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Demo/Scripts/PrimitiveGenerator.cs:50)
    UnityEngine.EventSystems.EventSystem:Update()
    "
     
  9. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Everything has been resolved! It was poor preparation on my part, not anything to do with the plugin haha. This thing is great and the usability is beyond simple. My case was a challenge using scriptable objects but by referencing game objects and serializing those and then reading the scriptable objects back via a reference, that fixed my issue. Again; my poor set up, nothing with the CPES!

    Thank you again for the support in the DM’s, prompt and helpful.
     
    Voxel-Busters likes this.
  10. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Thank you. We appreciate your kindness and support :) We will add new cool features like optimising object serialization automatically based on usage. If you need anything from us, please feel free to ask. We will make sure to provide best support possible.

    Thank you
    VB Team
     
    Duffer123 likes this.
  11. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @Voxel-Busters ,

    Have just purchased! ;) Just out of curiosity (and it will no doubt come up later) - what's the best approach to take with ScriptableObjects which might say be the core base templates for say Items in an RPG or similar? (in terms of references to them in Prefabs or GOs)?
     
  12. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Cool. Thank you for your trust on the product.

    Regarding your doubt, does this scriptableObject exist in the project as an asset file? Current version doesn't have support to scriptable object, but we can add this support and publish the build. We would like to know about your requirement and based on that suggest you solution.

    Btw, our team just shared a stress test video of serialising complex gameObjects. Please watch it from here:
     
    HakJak and Duffer123 like this.
  13. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @Voxel-Busters ,

    Timely tutorial!

    I suppose in-game saving and loading only requires reliable saving of reference to ScriptableObjects?

    Excellent vid!

    If I save out a GO can/does it save with the GO all its components AND all hierarchical children, grandchildren and their components, all in the one saving of GO method?
     
  14. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Yes, thats correct. We will release minor version with support to retain ScriptableObject reference.

    As we showed in the last video, plugin can literally save anything you throw at it. But it's always in the best interest of developer to save only the properties which are required for restoring state. This step helps you run game smoother.

    Yes, there are 2 ways to control this:
    1) Global Settings -> Serialization Method: Here enable the options according to your preference. By default, whole hierarchy will be serialized along with its attached components. This settings acts like global settings for all serialization requests. Watch Plugin Setup video and follow the steps.
    2) You can also override global settings, by providing custom SerializationOptions (available option are storage location, buffersize and SerializationMethodOption).
     
    Duffer123 likes this.
  15. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Quick update, we have submitted new version for review which includes support for SerializedObject types. You can expect it to be available in next 1-2 business days.

    We are eager to know your thoughts about this new products. So please don't forgot to share your views with us and also write a review if possible :) Your inputs will help us improve this product and make it one of the best products out there in Asset Store.
     
  16. GBCFraser

    GBCFraser

    Joined:
    Apr 11, 2013
    Posts:
    94
    Hey Man I just got your Asset from the store. Working through the documentation.
    I get a strange error when I try to save a Gameobject with a Shader. An empty shader seems to totally freak out. But I threw a shader in, and it fixed some errors but I get a null shader exception.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using VoxelBusters.Serialization;
    5. public class SaveLoadHandler : MonoBehaviour {
    6.     private List<GameObject> m_spawnedList = new List<GameObject>();
    7.     public GameObject player;
    8.     public GameObject prefab;
    9.     // Use this for initialization
    10.     void Start () {
    11.         player = SerializationUtility.Instantiate(prefab);
    12.         m_spawnedList.Add(player);
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update () {
    17.     }
    18.  
    19.     public void Save()
    20.     {
    21.         SerializationManager.Serialize("player", player);
    22.     }
    23.  
    24.  
    25.     public void Load()
    26.     {
    27.         GameObject gameobject = SerializationManager.Deserialize<GameObject>("player");
    28.         player = gameobject;
    29.  
    30.     }
    31. }
    See pic below.
    Figure 1. The Error list. A simple cube I'm trying to save.
    Figure 2. The code the compiler complains about.

    What am I doing wrong when serializing Game Objects?
    Its just a simple cube. I must be doing something stupid.:)
     

    Attached Files:

    Last edited: Nov 23, 2018
    Duffer123 likes this.
  17. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    1 Question, have you added your scene in build settings? Incase you miss doing it, you will get runtime error for missing shader. And I can think of only this as the potential reason for the reported unusual behaviour. Please confirm.

    Edit: Also, can you please let us know the Unity version you are using?
     
    Last edited: Nov 24, 2018
  18. GBCFraser

    GBCFraser

    Joined:
    Apr 11, 2013
    Posts:
    94
    Thank you for your swift reply.
    I am using unity3d Version 2018.2.16f1.

    No I did not add the scene to the build settings. But I did now. After I added the scenes to the build, nothing happened still the same texture loading/deserialization error.
    Also the demo scene, "SceneSerialisation" is not working, even after adding to the build settings.

    Demo Scene:
    I get the same no texture/no material error, a magenta cube.
    When the object deserialized. I don't get all of them only 2 or 1. But mostly 2.
    They don't have their original name, instead they're named "New Game Object".

    In addition to the above warning on deserialization, i get a warning on serialization which led me to some of your code "ResourceObjectIdentifierStoreManager"
    Simple GameObjects without shaders or meshes seem to work fine.
    The two screenshots describe the warnings and serialization/deserialization results. The error code is the same as above.

    So the idStore == null ? Is that important?
     

    Attached Files:

  19. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Thank you for your reply. We will schedule a test on above mentioned unity version and find out whats causing this error. We will try to get back to you at the earliest possible.
     
    Duffer123 likes this.
  20. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi,
    Thanks for reporting. We just found the issue and please update this file in your project (one line changed).
    We are also attaching a video on how the setup for Scene Serialization needs to be. We update the same on the tutorials section too soon.

    Cheers,
    VB Team
     
    Duffer123 likes this.
  21. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    #CyberWeekMegaSale - 50% discount on all Voxel Busters products, offer lasts until Dec 8, 2018. Go get your copy now @ Unity Asset Store. Link: http://bit.ly/2P6ahYR

    600x1200CyberSalePromo.png

    Thank you
    VB Team
     
    Last edited: Nov 30, 2018
  22. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Version 1.3 pushed to Asset Store for review.
    * Fixed 2018.3 warnings

    Thanks & Regards,
    VB Team
     
  23. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @Voxel-Busters ,

    Excellent. So great to see this still being developed/enhanced...
     
    Voxel-Busters likes this.
  24. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Duffer123 likes this.
  25. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    ArgumentException: An item with the same key has already been added. Key: UnityEngine.SceneManagement.Scene
    System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    VoxelBusters.Serialization.SceneObjectIdentifierStoreManager.GetStore (UnityEngine.SceneManagement.Scene scene) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/SceneObjects/SceneObjectIdentifierStoreManager.cs:352)
    VoxelBusters.Serialization.SceneObjectIdentifierStoreManager.HandleGameObjectCreated (UnityEngine.SceneManagement.Scene scene, UnityEngine.GameObject gameObject, System.String guid) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/SceneObjects/SceneObjectIdentifierStoreManager.cs:216)
    VoxelBusters.Serialization.SceneHierarchyModificationProcessor.DidCreateGameObject (UnityEngine.GameObject gameObject, System.String guid) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/Processors/SceneHierarchyModificationProcessor.cs:31)
    VoxelBusters.Serialization.SerializationUtility.CreateGameObject (System.String name) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/SerializationUtility.cs:36)
     
  26. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Hello,
    The following is update some code for SampleSererializationExample.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using VoxelBusters.Serialization;

    namespace VoxelBusters.Serialization.Examples
    {
    public class SampleSerializationExample : MonoBehaviour
    {
    #region Fields

    byte[] data;
    private Sample m_sampleObject;
    public Text m_text;

    #endregion

    #region Unity methods

    private void Awake()
    {
    UpdateText();
    }

    #endregion

    #region Private methods

    private void UpdateText()
    {
    if (m_sampleObject == null)
    {
    m_text.text = "Sample is NULL";
    }
    else
    {
    m_text.text = m_sampleObject.ToString();
    }
    }

    #endregion

    #region UI callback methods

    public void CreateInstance()
    {
    m_sampleObject = new Sample();
    m_sampleObject.SetRandomValues();

    UpdateText();
    }

    public void Serialize()
    {
    data = SerializationManager.SerializeToByteArray(m_sampleObject);
    //SerializationManager.Serialize(key: "Sample", value: m_sampleObject);
    }

    public void Deserialize()
    {
    //m_sampleObject = SerializationManager.Deserialize<Sample>(key: "Sample");
    m_text.text = "Empty";
    StartCoroutine(process());
    //m_sampleObject = SerializationManager.DeserializeFromByteArray<Sample>(data);
    //UpdateText();
    }

    public IEnumerator process()
    {
    yield return new WaitForSeconds(3);
    m_sampleObject = SerializationManager.DeserializeFromByteArray<Sample>(data);
    UpdateText();
    yield return null;
    byte[] t = SerializationManager.SerializeToByteArray<GameObject>(this.gameObject);
    //DestroyImmediate(this.gameObject);
    yield return null;

    GameObject n = SerializationManager.DeserializeFromByteArray<GameObject>(t);
    n.name = "New Serialize Example";
    }

    #endregion
    }
    }


    //////////////// Then when click Deserialize, the exception occur, then only empty deserialized object created ////


    ArgumentException: An item with the same key has already been added. Key: UnityEngine.SceneManagement.Scene
    System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    VoxelBusters.Serialization.SceneObjectIdentifierStoreManager.GetStore (UnityEngine.SceneManagement.Scene scene) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/SceneObjects/SceneObjectIdentifierStoreManager.cs:352)
    VoxelBusters.Serialization.SceneObjectIdentifierStoreManager.HandleGameObjectCreated (UnityEngine.SceneManagement.Scene scene, UnityEngine.GameObject gameObject, System.String guid) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/SceneObjects/SceneObjectIdentifierStoreManager.cs:216)
    VoxelBusters.Serialization.SceneHierarchyModificationProcessor.DidCreateGameObject (UnityEngine.GameObject gameObject, System.String guid) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/IdentifierSystem/Processors/SceneHierarchyModificationProcessor.cs:31)
    VoxelBusters.Serialization.SerializationUtility.CreateGameObjectWithGuid (System.String guid) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/SerializationUtility.cs:58)
    VoxelBusters.Serialization.UnityEngine_GameObjectDataProvider.CreateInstance (VoxelBusters.Serialization.IObjectReader reader, VoxelBusters.Serialization.SerializationContext context) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/DataProviders/UnityEngine_GameObjectDataProvider.cs:57)
    VoxelBusters.Serialization.ObjectReader.ReadObject[T] (VoxelBusters.Serialization.StreamObject streamObject) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/Stream/ObjectReader.cs:1110)
    VoxelBusters.Serialization.ObjectReader.ReadPropertyInternal[T] (VoxelBusters.Serialization.IStreamObject streamObject) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/Stream/ObjectReader.cs:343)
    VoxelBusters.Serialization.ObjectReader.ReadProperty[T] () (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/Stream/ObjectReader.cs:242)
    VoxelBusters.Serialization.SerializationManager.DeserializeFromByteArray[T] (System.Byte[] data, System.String tag) (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Scripts/SerializationManager.cs:876)
    VoxelBusters.Serialization.Examples.SampleSerializationExample+<process>d__8.MoveNext () (at Assets/Plugins/VoxelBusters/CrossPlatformEasySave/Demo/Scripts/SampleSerializationExample.cs:79)
    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
     
  27. HakJak

    HakJak

    Joined:
    Dec 2, 2014
    Posts:
    192
    Any plans to add console support?
     
  28. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    We've submitted fix for this issue and its currently available @UnityAssetStore. Please update your copy and start using it.

    Happy coding!
     
  29. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Honestly we haven't tested it on console platform. But as the product is platform agnostic, it should work straight away. And incase if you face any issues, we will be happy to help.

    Btw if you are interested to test it on console, we can provide you a free voucher :)
     
    HakJak likes this.
  30. Biggix

    Biggix

    Joined:
    Dec 8, 2014
    Posts:
    44
    Does this plugin save to specific files? Because right now I only see keys in the documentation (not the file names)
     
    Voxel-Busters likes this.
  31. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @Voxel-Busters ,

    Can this Asset save out / load in any in-scene instantiated Prefabs with their runtime components and variable values?
     
    Last edited: Mar 24, 2019
  32. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi @Biggix,

    The usage of key value, depends on save target option (PlayerPrefs or LocalDisk) selected during save operation. Consider user selects PlayerPrefs as storage target, then key is used as key of PlayerPrefs. Whereas for LocalDisk as target, key is used as file name. These things are automatically handled internally by the plugin.

    Hope this answers your query.

    Thank you
    VB Team
     
  33. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hello @Duffer123,

    Yes it can save and restore Prefabs.

    And FYI, any asset referred in Scene will be saved based on its guid and thus provides advantage of keeping your output data (serialized data) compact. In the below shared video, almost all the components such as MeshRenderers, Materials, Textures, AnimatorController components etc are all saved based on guid. That's one of the advantages of using our products :)



    Hope you like it :)

    Thank you
    VB Team
     
    Duffer123 likes this.
  34. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Quick question: when saving to local disk, is it saves in Application.persistantDataPath ? I’m thinking of implementing iCloud data save / load with CPES and I have all of my player variables serialized perfectly. Now I want to make sure I can take those files and upload them to a cloud service so players can have their content across devices!
     
    Duffer123 likes this.
  35. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Good question, you can do it using File read operations and yes, they are placed in Application.persistentDataPath / folder name specified in Settings window of serialization plugin. But there's a better way to do it, which can avoid File operations. Here's the code snippet for it:

    Code (CSharp):
    1.  
    2. // save operation
    3. // step 1: convert to serialized form
    4. byte[]             instanceRawData    = SerializationManager.SerializeToByteArray(instance);
    5. // step 2: save byte array on cloud
    6.  
    7. // reload operation
    8. // step 1: read saved byte[] from cloud server
    9. // step 2: restore original object using raw data
    10. ExampleClass     savedInstance     = SerializationManager.DeserializeFromByteArray<ExampleClass>(instanceRawData);
    Hope this answer helps you :)

    Update : Please check here for the tutorial on the same.
     
    Last edited: Apr 2, 2019
    chaseholton likes this.
  36. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    Oh this is great! Thanks guys. When it comes to step 2... Do you have a recommended method for saving to the cloud? For example have quite a few variables I'm saving and loading on death / respawn / checkpoints throughout the game like:


    Code (CSharp):
    1.     public void SaveAllData()
    2.     {
    3.         Debug.Log("Save player Exp, gold, level, banked info, etc...");
    4.         SerializationManager.Serialize("bankedObjects", bankedGO);
    5.         SerializationManager.Serialize("bankedGold", bankedGold);
    6.         SerializationManager.Serialize("runeDust", runeDust);
    7.         SerializationManager.Serialize("changedRunes", runeChangesGO);
    8.         SerializationManager.Serialize("inventoryUpgradeCost", inventoryUpgradeCost);
    9.         SerializationManager.Serialize("shieldUpgradeCost", shieldUpgradeCost);
    10.         SerializationManager.Serialize("gold", gold);
    11.         SerializationManager.Serialize("playerExp", playerExpPoints);
    12.         SerializationManager.Serialize("playerLevel", playerLevel);
    13.         SerializationManager.Serialize("slot1Infinite", slot1Infinite);
    14.         SerializationManager.Serialize("slot2Infinite", slot2Infinite);
    15.         SerializationManager.Serialize("slot3Infinite", slot3Infinite);
    16.         SerializationManager.Serialize("slot4Infinite", slot4Infinite);
    17.         SerializationManager.Serialize("slot5Infinite", slot5Infinite);
    18.         SerializationManager.Serialize("infinifyLevel", infinifyLevel);
    19.         Inventory.instance.SaveInventory();
    20.         TattooistManager.instance.SaveTattooistData();
    21.  
    22.     }
    And when loading for example just this:

    Code (CSharp):
    1.         if (SerializationManager.HasKey("playerLevel"))
    2.         {
    3.             playerLevel = SerializationManager.Deserialize<int>("playerLevel");
    4.         }
    Would I be replacing these all with those conversions you recommended? Or is there a way to simple access the folder that is containing this files in the PersistentDataPath/folder_name and uploading them using cloud Documents, for instance, on iCloud? And just saving and loading the entire folder that way? Or is that way too vague of a question haha.
     
  37. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    This product provides a unique way of packing multiple data items and saving them into a single document. You can do this by using BeginSerializeGroup and EndSerializeGroup methods. We have a video tutorial to demonstrate this, please check it using this link.

    But currently these batching methods are available only for saving as a file or to PlayerPrefs. Anyways our team has added similar methods for directly accessing byte data which will be helpful for usecase like yours. We've submitted these changes to AssetStore for review. And I will update you as soon as it is approved.
     
  38. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78

    Your team’s responsiveness and willingness to help explain and link to further documentation is truly remarkable. Thank you so much for taking the time to address my issues and help in the already daunting task of game development. Especially with something as important as saving progress and cross platform for that matter.

    CPES is my first asset recommendation I give to any new indie devs using Unity.

    Cheers! Thanks again.
     
    Voxel-Busters likes this.
  39. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi again, new version is available now! We will share documentation link for new methods at the earliest possible. Meanwhile you can check our offline documentation provided along with the package. The methods useful for your requirement are: BeginSerializeToByteArrayGroup and BeginDeserializeToByteArrayGroup.

    Here's the example code for your reference.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using VoxelBusters.Serialization;
    5.  
    6. public class ChaseExample : MonoBehaviour
    7. {
    8.     int     inventoryUpgradeCost;
    9.     int     shieldUpgradeCost;
    10.     int     gold;
    11.     int     playerExpPoints;
    12.     int     playerLevel;
    13.     int     slot1Infinite;
    14.     int     slot2Infinite;
    15.     int     slot3Infinite;
    16.     int     slot4Infinite;
    17.     int     slot5Infinite;
    18.     bool    infinifyLevel;
    19.  
    20.     void Save ()
    21.     {
    22.         // batching calls to write data to same block
    23.         SerializationManager.BeginSerializeToByteArrayGroup();
    24.         SerializationManager.Serialize("inventoryUpgradeCost", inventoryUpgradeCost);
    25.         SerializationManager.Serialize("shieldUpgradeCost", shieldUpgradeCost);
    26.         SerializationManager.Serialize("gold", gold);
    27.         SerializationManager.Serialize("playerExp", playerExpPoints);
    28.         SerializationManager.Serialize("playerLevel", playerLevel);
    29.         SerializationManager.Serialize("slot1Infinite", slot1Infinite);
    30.         SerializationManager.Serialize("slot2Infinite", slot2Infinite);
    31.         SerializationManager.Serialize("slot3Infinite", slot3Infinite);
    32.         SerializationManager.Serialize("slot4Infinite", slot4Infinite);
    33.         SerializationManager.Serialize("slot5Infinite", slot5Infinite);
    34.         SerializationManager.Serialize("infinifyLevel", infinifyLevel);
    35.         byte[] data = SerializationManager.EndSerializeToByteArrayGroup();
    36.  
    37.         // use cloud service to save byte array
    38.  
    39.     }
    40.  
    41.     void Load()
    42.     {
    43.         // get byte array which was saved earlier on cloud
    44.         byte[] data = null;
    45.  
    46.         // open this data using deserializer
    47.         SerializationManager.BeginDeserializeToByteArrayGroup(data);
    48.         inventoryUpgradeCost    = SerializationManager.Deserialize<int>("inventoryUpgradeCost");
    49.         shieldUpgradeCost       = SerializationManager.Deserialize<int>("shieldUpgradeCost");
    50.         gold                    = SerializationManager.Deserialize<int>("gold");
    51.         playerExpPoints         = SerializationManager.Deserialize<int>("playerExp");
    52.         playerLevel             = SerializationManager.Deserialize<int>("playerLevel");
    53.         slot1Infinite           = SerializationManager.Deserialize<int>("slot1Infinite");
    54.         slot2Infinite           = SerializationManager.Deserialize<int>("slot2Infinite");
    55.         slot3Infinite           = SerializationManager.Deserialize<int>("slot3Infinite");
    56.         slot4Infinite           = SerializationManager.Deserialize<int>("slot4Infinite");
    57.         slot5Infinite           = SerializationManager.Deserialize<int>("slot5Infinite");
    58.         infinifyLevel           = SerializationManager.Deserialize<bool>("infinifyLevel");
    59.         SerializationManager.EndDeserializeToByteArrayGroup();
    60.     }
    61. }
    62.  
     
    Last edited: Apr 8, 2019
    chaseholton likes this.
  40. chaseholton

    chaseholton

    Joined:
    Dec 17, 2012
    Posts:
    78
    You. Are. All. Legends!!! Thank you thank you! This is going to make cloud saving a cinch without needing a second plugin!

    Awesome. I’m going to implement this tonight or sooner. ASAP. 10/5 stars. Yes.
     
  41. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    hi. interested in this pkugin. have few questions.

    1. if i want to save a game object in the scene, how can i selectively only save which components and what variables within the component ?

    2. upon deserializing game object, i want to use existing game object in the scene and replace its properties , values only. because i dont want to instantiate a new object due to breaking my references to that game object from other game objects. is this possible?

    3. when deserializing, if new game object instantiation is necessary, how does system know what game object to instantiate? this question is related to my first question, because for some game objects with custom components/classes I actually dont want to seralize it. say for example if i have some components that are not required to save, like some custom class i am expecting the deserializer to just instantiate a new prefab and then replace data on it. do i have to add this particular prefabs into resources folder?

    so basically for deserializing, if game object exist, it should only replace/update data to it, and if the game object does not exist it should instantiate one and replace data to it.

    thanks.
     
  42. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Apologies for the delayed response. Please check the answers below.

    1. if i want to save a game object in the scene, how can i selectively only save which components and what variables within the component ?

    Can be done by batching calls. Basically you are controlling the data items to be saved and plugin will do the rest.

    2. upon deserializing game object, i want to use existing game object in the scene and replace its properties , values only. because i dont want to instantiate a new object due to breaking my references to that game object from other game objects. is this possible?

    Yes, possible. (We maintain custom allocated guid's created by our system and use it to refer the existing gameobjects if they already exist. If we don't find them, we instantiate a new object, else use the existing one. )

    3. when deserializing, if new game object instantiation is necessary, how does system know what game object to instantiate? this question is related to my first question, because for some game objects with custom components/classes I actually dont want to seralize it. say for example if i have some components that are not required to save, like some custom class i am expecting the deserializer to just instantiate a new prefab and then replace data on it. do i have to add this particular prefabs into resources folder?

    You don't need to add any prefabs or assets specially as we track the used prefabs automatically in edit time (when ever you save a scene). So basically for deserializing, if game object exist, it should only replace/update data to it, and if the game object does not exist it should instantiate one and replace data to it.
     
    Last edited: Jun 3, 2019
    Duffer123 likes this.
  43. GiraffeAndAHalf

    GiraffeAndAHalf

    Joined:
    Dec 28, 2018
    Posts:
    10
    Hi, I'm having some trouble serializing my data (Actually two things but I'll start with the simpler).
    I have some arrays of structs which are passed around by reference, in a custom class akin to the List Collection, but with very few features, (doing this for the purpose of increasing cache performance). Simplified sample code below.
    Code (CSharp):
    1.  
    2. namespace abc {
    3.     // Just a sample easy struct.
    4.     [System.Serializable]  
    5.     public struct Sample { public int a; public int b; }
    6.  
    7.     // An example of the kind of data structure I'm trying to save.
    8.     [System.Serializable]  
    9.     public class RefStructArraySample {
    10.         [SerializeField] publicSample[] arr;
    11.         [SerializeField] public int capacity = 128;
    12.         [SerializeField] public int count = 0;
    13.         public RefStructArraySample() {
    14.             arr = new Sample[capacity];
    15.         }
    16.         public int Add(Sample s) {
    17.             if (count >= capacity) {
    18.                 int newCap = capacity * 2;
    19.                 Sample[] newArr = new Sample[newCap];
    20.                 CopyInto(capacity, arr, newArr);
    21.                 capacity = newCap;
    22.                 arr = newArr;
    23.             }
    24.             arr[count++] = s;
    25.             return count;
    26.         }
    27.         public ref Sample GetRef(int index) {
    28.             if (index > count - 1) {
    29.                 throw new Exception("index invalid (" + index + "): of array sized to " + count + "/" + capacity);
    30.             }
    31.             return ref arr[index];
    32.         }
    33.         private void CopyInto(int numItems, Sample[] oldArr, Sample[] newArr) {
    34.             for (int i = 0; i < numItems; ++i) {
    35.                 newArr[i] = oldArr[i];
    36.             }
    37.         }
    38.         public int GetCapacity() { return capacity; }
    39.         public int GetCount() { return count; }
    40.     }
    41. }
    42.  
    43.  
    When I try to use Window->VoxelBusters->CPES->GenerateDataProvider for this class I just get the following error:

    [Serialization] Couldn't generate code for type: abc.RefStructArraySample
    UnityEngine.Debug:LogWarning(Object)
    VoxelBusters.Serialization.SerializationDataProviderGeneratorWindow:OnGUI() (at Assets/Editor/VoxelBusters/CrossPlatformEasySave/Scripts/SerializationDataProviderGeneratorWindow.cs:119)
    UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)


    If I try to Serialize and then Deserialize this data without creating its own DataProvider, I get the following when using the below code:
    RefStructArraySample will now be serialized, with count/capacity of 1000/1024
    RefStructArraySample has been deserialized, and has count/capacity of 0/128

    So you can see that the array and inner values are not being serialized/deserialized.
    Code (CSharp):
    1. namespace abc {
    2.     public class RefStructArraySampleUser : MonoBehaviour {
    3.         RefStructArraySample rsas = new RefStructArraySample();
    4.         readonly string rsasName = "refStructArrayName";
    5.  
    6.         void Start() {
    7.             Sample s = new Sample();
    8.             for (int i = 0; i < 1000; ++i) {              
    9.                 s.a = s.b = i;
    10.                 rsas.Add(s);
    11.             }
    12.         }
    13.  
    14.         // Hooked up to a button.
    15.         public void SaveSamples() {
    16.             Debug.Log("RefStructArraySample will now be serialized, with count/capacity of " + rsas.GetCount() + "/" + rsas.GetCapacity());
    17.             VoxelBusters.Serialization.SerializationManager.Serialize<abc.RefStructArraySample>(rsasName, rsas);
    18.         }
    19.  
    20.         // Hooked up to a button.
    21.         public void LoadSamples() {
    22.             RefStructArraySample s = VoxelBusters.Serialization.SerializationManager.Deserialize<abc.RefStructArraySample>(rsasName);
    23.             Debug.Log("RefStructArraySample has been deserialized, and has count/capacity of " + s.GetCount() + "/" + s.GetCapacity());
    24.         }
    25.     }
    26. }
     
  44. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi,

    Sorry for the inconvenience caused.

    Can we continue this conversation using DM? If possible can you please share sample project having this issue?

    Thank you
    VB Team
     
  45. Wanghaifeng

    Wanghaifeng

    Joined:
    Aug 13, 2019
    Posts:
    1
    Excuse me,How do I save scriptableObject?
     
  46. GiraffeAndAHalf

    GiraffeAndAHalf

    Joined:
    Dec 28, 2018
    Posts:
    10
    I started another clean project to send you a minimal sample and its working there! I;m not seeing any differences in settings so maybe something got corrupted or maybe I imported an older version of the save utility.

    In any case, we're good, thanks, product working very well so far!
     
    Voxel-Busters likes this.
  47. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Thanks for the update! Please feel free to DM us, incase if you have any doubts/questions.
     
  48. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi, we use generic template for save/load calls, so that users don't need to use a separate API for saving different types of object. So to answer your question, it is same like saving a float except that you have to pass a scriptable object reference as shown in this post.

    Example:
    Code (CSharp):
    1. ScriptableObject obj = someValue;
    2. SerializationManager.Serialize<ScriptableObject>("test", obj);
    Thank you
     
    Last edited: Aug 16, 2019
  49. ttermeer-reboundcg

    ttermeer-reboundcg

    Joined:
    Jul 12, 2017
    Posts:
    62
    @Voxel-Busters do you have any benchmark on loading times compared to loading a scene ? I don't think it is your plugin intention but we are looking into alternative way to load scene with a high number of object. Unity scene system is way too slow.
     
  50. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    1,963
    Hi, Unfortunately no. We do not have any test results comparing instantiating objects using plugin vs loading a scene. And, the reason is we are not considering this plugin to work as an alternative to Unity scene loading mechanism. Actually plugin works in synchronous manner whereas Unity supports async based scene loading. So at this point, we don't recommend our plugin to be used that way.

    Thank you!
     
    ttermeer-reboundcg likes this.