Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved Serialization error on a delegate

Discussion in 'Scripting' started by Pierre-Marie, Mar 27, 2023.

  1. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    51
    Hi,

    I have a class PlayerEntityData wich basicly contain information about the player character. I have a Save and Load system That serialized the player data and load it when you load your save.

    I recently add a delegate in that class wich doesn't seem to support this serialization process.
    there is the script :


    Code (CSharp):
    1. using Assets._02_Managers;
    2. using Assets.WorkObjects.InventoriesData;
    3. using Assets.WorkObjects.Ship;
    4. using System;
    5. using UnityEditor;
    6. using UnityEngine;
    7.  
    8.  
    9. namespace TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities
    10. {
    11.     [System.Serializable]
    12.     public class PlayerEntityData : DynamicEntityData
    13.     {
    14.  
    15.        
    16.         public delegate void onWeaponChangeDelegate(string newWeapon);
    17.         [NonSerialized]
    18.         public onWeaponChangeDelegate OnWeaponChange;
    19.         public string playerName { get; set; } = "";
    20.         /// <summary>
    21.         /// l'heure du derrnier click pour savoir si c'est un clic simple ou un double clic
    22.         /// </summary>
    23.         public float lastClickTime;
    24.  
    25.         // des string avec le code hexadécimal des couleurs du thème du joueur
    26.         // pour convertir ColorUtility.TryParse
    27.         //ColorUtility.TryParseHtmlString(htmlValue, out newColor)
    28.         public string Settings_Color_Primary { get; set; }
    29.         public string Settings_Color_Secondary { get; set; } = "";
    30.         public string Settings_Color_Leather_Primary { get; set; } = "";
    31.         public string Settings_Color_Metal_Primary { get; set; } = "";
    32.         public string Settings_Color_Metal_Secondary { get; set; } = "";
    33.         public string Settings_Color_Leather_Secondary { get; set; } = "";
    34.         public string Settings_Color_Metal_Dark { get; set; } = "";
    35.         public string Settings_Color_Hair { get; set; } = "";
    36.         public string Settings_Color_Skin { get; set; } = "";
    37.         public string Settings_Color_Stubble { get; set; } = "";
    38.         public string Settings_Color_Scar { get; set; } = "";
    39.         public string Settings_Color_BodyArt { get; set; } = "";
    40.         public string Settings_Color_Eyes { get; set; } = "";
    41.  
    42.  
    43.         public ShipData shipData;
    44.         public int weaponLevel;
    45.         public int armorLevel;
    46.         public int ringLevel;
    47.         public int bootLevel;
    48.         public int grimoirLevel;
    49.         public int necklaceLevel;
    50.         public string weaponType { get; private set; }
    51.  
    52.         #region constructeur
    53.         /// <summary>
    54.         /// cosntructeur sans argument
    55.         /// </summary>
    56.         public PlayerEntityData () : base()
    57.         {
    58.             shipData = new ShipData();
    59.            
    60.         }
    61.  
    62.         /// <summary>
    63.         /// Constructeur de recopie
    64.         /// </summary>
    65.         /// <param name="playerEntityData"></param>
    66.         public PlayerEntityData (PlayerEntityData playerEntityData) : base()
    67.         {
    68.             lastClickTime = playerEntityData.lastClickTime;
    69.             shipData = new ShipData();
    70.             //RessourceType = playerEntityData.RessourceType;
    71.         }
    72.  
    73.         /// <summary>
    74.         /// Constructeur de recopie à partir d'une instance du parent
    75.         /// </summary>
    76.         /// <param name="dynamicEntityData"></param>
    77.         public PlayerEntityData(DynamicEntityData dynamicEntityData)
    78.         {
    79.             //Debug.Log("player constructeur de recopie !!");
    80.             this.InitialHealth = dynamicEntityData.InitialHealth;
    81.             this.HealthPoint = dynamicEntityData.HealthPoint;
    82.             this.MaxHealthPoint = dynamicEntityData.MaxHealthPoint;
    83.             this.MaxHealthPoint = dynamicEntityData.MaxHealthPoint;
    84.             this.HealthRecoveryRate = dynamicEntityData.HealthRecoveryRate;
    85.             this.ManaPoint = dynamicEntityData.ManaPoint;
    86.             this.NaturalInitialManaPoint = dynamicEntityData.NaturalInitialManaPoint;
    87.             this.MaxManaPoint = dynamicEntityData.MaxManaPoint;
    88.             this.ManaRecoveryRate = dynamicEntityData.ManaRecoveryRate;
    89.  
    90.             this.HealthLastFrame = dynamicEntityData.HealthLastFrame;
    91.             this.RessourceLastFrame = dynamicEntityData.RessourceLastFrame;
    92.            
    93.             this.InventoryData = dynamicEntityData.InventoryData;
    94.  
    95.             this.NaturalBasicAttackData = dynamicEntityData.NaturalBasicAttackData;
    96.             this.BasicAttackData = dynamicEntityData.BasicAttackData;
    97.  
    98.             this.dynamicEntityVisual = dynamicEntityData.dynamicEntityVisual;
    99.             this.unlockVisualList = dynamicEntityData.unlockVisualList;
    100.             shipData = new ShipData();
    101.         }
    102.  
    103.         #endregion
    104.  
    105.         //public new void refreshData()
    106.         //{
    107.         //    base.refreshData();
    108.         //}
    109.         public void SetWeaponType(string newWeaponType)
    110.         {
    111.             weaponType = newWeaponType;
    112.             //OnWeaponChange?.Invoke(newWeaponType);
    113.         }
    114.     }
    115. }
    the problematics lines are :

    Code (CSharp):
    1. public delegate void onWeaponChangeDelegate(string newWeapon);
    2.         [NonSerialized]
    3.         public onWeaponChangeDelegate OnWeaponChange;
    When the save and load manager try to deserialize un save

    Code (CSharp):
    1. XmlSerializer serializer = new XmlSerializer(typeof(GameData));
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities;
    4. using UnityEngine;
    5.  
    6. [System.Serializable]
    7.  
    8.  
    9. public class GameData
    10. {
    11.     public long lastUpdated;
    12.     public PlayerEntityData playerData;
    13.     //public GameObject World;
    14.     public string LastScene;
    15.     //public Vector3 playerPosition;
    16.  
    17.     public GameData()
    18.     {
    19.         playerData = new PlayerEntityData();
    20.         LastScene = "playerCreationScene";
    21.     }
    22. }
    I have an error and when I comment those lines it work just fine.


    Code (CSharp):
    1. Error occured when trying to load Game : C:/Users/Pimous/AppData/LocalLow/DefaultCompany/TowerDefenseTest\2\testSave.game
    2. System.InvalidOperationException: There was an error reflecting type 'GameData'. ---> System.InvalidOperationException: There was an error reflecting field 'playerData'. ---> System.InvalidOperationException: There was an error reflecting type 'TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities.PlayerEntityData'. ---> System.InvalidOperationException: Cannot serialize member 'TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities.PlayerEntityData.OnWeaponChange' of type 'TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities.PlayerEntityData+onWeaponChangeDelegate', see inner exception for more details. ---> System.InvalidOperationException: TowerDefense.Assets.WorkObjects.DynamicsEntities.PlayersEntities.PlayerEntityData.onWeaponChangeDelegate cannot be serialized because it does not have a parameterless constructor.
    3.  
    the error message want me to create a parameterless constructor for 'onWeaponChangeDelegate' but I tagged it as [NonSerialized] cause I don't need it to be save and it's strange to creat a cosntructor for a delegate.

    Is there a way to make the serialization ignor that delegate?
    I asked ChatGPT but it tell me that the code is fine and the error should be related to some other code :(.

    Thanks for your help human friends.
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,225
    The error is coming from your save and load system, NonSerialized is a Unity serializer tag that is likely ignored by the other system. See if the system you are using has its own attribute to ignore the field.
     
    Bunny83 likes this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,915
    Right, the XmlSerializer has its own attributes, like XmlIgnore.

    (I hate having a lower case
    l
    (L) next to an uppercase
    I
    (i). That creates so much visual confusion ^^)
     
  4. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    51
    Hoo yeap that it!! For now Unity communauty still better than chatGPT.
    Thank's for your help!!
     
    richardkettlewell and karl_jones like this.