- Home /
Binary Save System error
Hi, thanks for your time this error message alone is a big one. the game has been on the backburner with everything going on I have time to work on it. when I first made this save system it worked just fine but after I move to the latest vers of unity I get this error on load.
Error"
SerializationException: Type 'UnityEngine.ScriptableObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (System.RuntimeType type) (at :0) System.Runtime.Serialization.FormatterServices+<>c_DisplayClass9_0.b0 (System.Runtime.Serialization.MemberHolder ) (at :0) System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at :0) System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, System.Runtime.Serialization.StreamingContext context) (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo () (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (System.Type objectType, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.SerializationBinder binder) (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (System.Type objectType, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.SerializationBinder binder) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo memberObjectInfo) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (System.Object graph, System.Runtime.Remoting.Messaging.Header[] inHeaders, System.Runtime.Serialization.Formatters.Binary.__BinaryWriter serWriter, System.Boolean fCheck) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers, System.Boolean fCheck) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph) (at :0) SaveSystem.Save () (at Assets/arena/Code/All_Mangers/SaveSystem.cs:141) GameControllerEditor.OnInspectorGUI () (at Assets/arena/Code/Editor/GameControllerEditor.cs:22) UnityEditor.UIElements.InspectorElement+<>c_DisplayClass58_0.b_0 () (at :0) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)"
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
using UnityEngine;
public class SaveSystem : MonoBehaviour {
public static SaveSystem saveSystem;
public int playerLevel = 1;
public float xp;
public float xpToNextLevel = 100;
public int skillPoints = 0;
public int gold = 0;
public bool hasGame;
public int numberOfEnemys = 1;
public float playerHeath = 100;
public bool hasSave;
[Header("Shop")]
public List<ShopStuff> shopList = new List<ShopStuff>();
public int mainWeaponID = 1;
public int sideWeaponID = 1;
public int helmetID;
public int chestID;
public int arrowsID;
public int bootsID;
public int gaunletsID;
public bool hasItem;
[Header("Inventory")]
public List<Item> items = new List<Item>();
[Header("Perks")]
public float drawSpeed = 260f;
public int drawSpeedDamage;
public int drawSpeedN;
public int AddHealth;
public int AddHealthN;
public float addStamina;
[Header("Level")]
public bool main;
public bool arena;
public bool trainig;
public bool death;
public bool Barracks;
public GameObject playerControlls;
[Header("Customize Character")]
public string playerName;
public GameObject levelUp;
public PlayerLevel playerLeveler;
[Header("Options")]
public float volume;
public bool music;
public bool fps;
public bool hasLoaded;
public Options options;
void Awake () {
if (saveSystem == null)
{
saveSystem = this;
LoadOptions();
Load();
}
else if (saveSystem != this)
{
Destroy(gameObject);
}
}
void Update()
{
if (xp >= xpToNextLevel)
{
playerLevel++;
skillPoints++;
xpToNextLevel += xpToNextLevel;
levelUp.SetActive(!levelUp.activeSelf);
}
if(main == false)
{
if(playerLeveler.hasSpentPoints == true)
{
playerLeveler.hasSpentPoints = false;
levelUp.SetActive(!levelUp.activeSelf);
}
}
}
public void Controlls()
{
playerControlls.SetActive(!playerControlls.activeSelf);
}
public void Save()
{
hasSave = false;
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/playerInfo.data");
PlayerData data = new PlayerData();
data.playerLevel = playerLevel;
data.xp = xp;
data.xpToNextLevel = xpToNextLevel;
data.skillPoints = skillPoints;
hasGame = true;
data.hasGame = hasGame;
data.gold = gold;
data.drawSpeed = drawSpeed;
data.drawSpeedNumber = drawSpeedN;
data.AddHealth = AddHealth;
data.AddHealthN = AddHealthN;
data.drawSpeedDamage = drawSpeedDamage;
data.numberOfEnemys = numberOfEnemys;
data.mainWeaponID = mainWeaponID;
data.sideWeaponID = sideWeaponID;
data.helmetID = helmetID;
data.chestID = chestID;
data.arrowsID = arrowsID;
data.bootsID = bootsID;
data.gaunletsID = gaunletsID;
data.hasItem = hasItem;
data.arena = arena;
data.death = death;
data.main = main;
data.trainig = trainig;
data.Barracks = Barracks;
data.playerHeath = playerHeath;
data.addStamina = addStamina;
data.playerName = playerName;
data.items = items;
data.shopList = shopList;
bf.Serialize(file, data);
file.Close();
hasSave = true;
Debug.Log("saved player data");
}
public void Load()
{
hasSave = false;
if (File.Exists(Application.persistentDataPath + "/playerInfo.data"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open (Application.persistentDataPath + "/playerInfo.data", FileMode.Open);
PlayerData data = (PlayerData)bf.Deserialize (file);
file.Close();
playerLevel = data.playerLevel;
xpToNextLevel = data.xpToNextLevel;
skillPoints = data.skillPoints;
xp = data.xp;
gold = data.gold;
drawSpeed = data.drawSpeed;
drawSpeedN = data.drawSpeedNumber;
AddHealth = data.AddHealth;
AddHealthN = data.AddHealthN;
hasGame = data.hasGame;
drawSpeedDamage = data.drawSpeedDamage;
numberOfEnemys = data.numberOfEnemys;
mainWeaponID = data.mainWeaponID;
sideWeaponID = data.sideWeaponID;
helmetID = data.helmetID;
chestID = data.chestID;
arrowsID = data.arrowsID;
bootsID = data.bootsID;
gaunletsID = data.gaunletsID;
shopList = data.shopList;
hasItem = data.hasItem;
death = data.death;
main = data.main;
trainig = data.trainig;
arena = data.arena;
Barracks = data.Barracks;
playerHeath = data.playerHeath;
addStamina = data.addStamina;
playerName = data.playerName;
items = data.items;
Debug.Log ("Laoded player data");
}
}
public void Delete()
{
hasSave = false;
File.Delete(Application.persistentDataPath + "/playerInfo.data");
playerLevel = 1;
skillPoints = 0;
xp = 0;
xpToNextLevel = 100;
gold = 0;
hasGame = false;
drawSpeed = 260f;
drawSpeedN = 0;
AddHealthN = 0;
AddHealth = 0;
drawSpeedDamage = 0;
numberOfEnemys = 1;
mainWeaponID = 1;
sideWeaponID = 1;
helmetID = 0;
chestID = 0;
arrowsID = 0;
bootsID = 0;
gaunletsID = 0;
hasItem = false;
playerHeath = 100;
main = true;
trainig = false;
arena = false;
death = false;
Barracks = false;
addStamina = 0;
playerName = "Player";
items.Clear();
Debug.Log ("player data has been deleted");
}
public void SaveOptions()
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/PlayerOption.data");
PlayerOptions optionsdata = new PlayerOptions();
optionsdata.volume = volume;
optionsdata.fps = fps;
optionsdata.music = music;
bf.Serialize(file, optionsdata);
file.Close();
Debug.Log("Saved Options");
}
public void LoadOptions()
{
if (File.Exists(Application.persistentDataPath + "/PlayerOption.data"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/PlayerOption.data", FileMode.Open);
PlayerOptions optionsdata = (PlayerOptions)bf.Deserialize(file);
file.Close();
music = optionsdata.music;
fps = optionsdata.fps;
volume = optionsdata.volume;
hasLoaded = true;
Debug.Log("Laoded Options");
}
else
{
Debug.Log("No options save to load");
music = true;
fps = true;
volume = .5f;
hasLoaded = true;
}
}
public void ResetOptions()
{
File.Delete(Application.persistentDataPath + "/PlayerOption.data");
music = true;
fps = true;
volume = .5f;
hasLoaded = true;
options.Load();
Debug.Log("Options have been Reset.");
}
}
[Serializable]
class PlayerOptions
{
public float volume;
public bool music;
public bool fps;
}
[Serializable]
class PlayerData
{
public int playerLevel;
public float xp;
public float xpToNextLevel;
public int skillPoints;
public int gold;
public int AddHealth;
public int AddHealthN;
public int drawSpeedNumber;
public int drawSpeedDamage;
public float drawSpeed;
public bool hasGame;
public int numberOfEnemys;
public List<ShopStuff> shopList = new List<ShopStuff>();
public float addStamina;
public bool hasItem;
public bool main;
public bool arena;
public bool trainig;
public bool death;
public bool Barracks;
public float playerHeath;
public string playerName;
public List<Item> items = new List<Item>();
public int mainWeaponID;
public int sideWeaponID;
public int helmetID;
public int chestID;
public int arrowsID;
public int bootsID;
public int gaunletsID;
}
Thanks agian for your time have a good day or night.
Your log says that GameControllerEditor.OnInspectorGUI()
calls SaveSystem.Save()
and everything brakes there in (closed-source) code of BinaryFormatter.Serialize()
This means that there is something wrong with some of the data you provided to this binary formatter
Stack trace ends with FormatterServices.InternalGetSerializable$$anonymous$$embers
calling UnityEngine.Core$$anonymous$$odule
and crash happens there. Reported reason being UnityEngine.ScriptableObject' (...) is not marked as serializable
. ̶S̶o̶ ̶e̶i̶t̶h̶e̶r̶ ̶t̶h̶a̶t̶ ̶s̶e̶r̶i̶a̶l̶i̶z̶e̶r̶ ̶w̶a̶n̶t̶'̶s̶ ̶P̶l̶a̶y̶e̶r̶D̶a̶t̶a̶ ̶t̶o̶ ̶b̶e̶ ̶a̶l̶s̶o̶ ̶p̶u̶b̶l̶i̶c̶ ̶(̶r̶e̶f̶l̶e̶c̶t̶i̶o̶n̶ ̶r̶e̶t̶u̶r̶n̶i̶n̶g̶ ̶n̶u̶l̶l̶?̶)̶ ̶O̶R̶ ̶P̶l̶a̶y̶e̶r̶D̶a̶t̶a̶ i̶t̶s̶e̶l̶f̶ ̶t̶o̶ ̶b̶e̶ ̶a̶n̶ ̶S̶c̶r̶i̶p̶t̶a̶b̶l̶e̶O̶b̶j̶e̶c̶t̶
hi, the GameControllerEditor adds buttons on save code in unity so I save, load delete. whit out having the ga$$anonymous$$g running.
Answer by Bunny83 · Jun 05, 2020 at 11:24 AM
Well there are exactly two possible reasons in the code that you've shown which will cause this issue. Either your "ShopStuff" class or your "Item" class is either derived from ScriptableObject or may contain a reference to another class that is derived from ScriptableObject. ScriptableObject derived classes can not be serialized at all by the BinaryFormatter. The first requirement for a class to be supported by the BinaryFormatter is that it's marked as serializable which ScriptableObject is not. We will see in a second why it's not. The second requirement is that all the data (fields) a class contains has to be serializable as well. Finally the class need to have a parameterless constructor (implicit or explicit) that can create an instance of that class during deserialization.
ScriptableObjects do not fulfill the last two points. ScriptableObjects have internal fields which are linked to native C++ objects in the engine code. So those "links" can not be serialized and restored at all. That's why the ScriptableObject class isn't marked as serializable in the first place. ScriptableObjects also can not be created with "new". You have to use CreateInstance which will not only create the managed object on the .NET side but also creates the corresponding object on the native C++ side. Therefore even when the BinaryFormatter could somehow serialize the class, it can're recreate it during deserialization.
There are several ways how to solve this. As I recommended countless of times already, I wouldn't recommend to use the BinaryFormatter at all. It's way too strict, quite verbose and intolerant to any structural changes to your classes. Anyways if you want to stick with the BinaryFormatter (for whatever reason) you essentially have two options: Get rid of any non serializable classes in your save data. So for the list of items the player has you probably only want to store a unique "item ID". So when reloading that data you should be able to use that ID to figure out which Item the player should have. Of course if the individual items can have other runtime parameters that are altered during gameplay, you have to save them as well, somehow. We can't go into detail here since we have no idea how your Item class looks like and how it's actually used. The second solution if you want to stick with the BinaryFormatter is to implement a serialization Surrogate for those unsupported classes. In the end this solution would be similar to the first one since you have to capture the essential information you need to store in your surrogate and also implement the reconstruction / re-linking yourself. Surrogates are a neat feature but it's questionable if it's worth it.
Instead of the BinaryFormatter you may want to use an alternative serialization format like JSON or your own custom binary format. The BinaryFormatter doesn't really buy you much since you still copying all sorts of values into and out of your PlayerData class manually. So you could simply use the BinaryReader / BinaryWriter and come up with your own binary save format which would be much smaller as well. I highly recommend to add a "version" field at the beginning in case you update (add / remove) your save data.
thanks for all your help it was something to do with the lists.
Answer by KillitsGaming · Jun 16, 2020 at 03:49 PM
thanks for helps guys its when i save it give me it SerializationException: Type 'UnityEngine.ScriptableObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (System.RuntimeType type) (at :0) System.Runtime.Serialization.FormatterServices+<>c_DisplayClass9_0.b0 (System.Runtime.Serialization.MemberHolder ) (at :0) System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at :0) System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, System.Runtime.Serialization.StreamingContext context) (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo () (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (System.Type objectType, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.SerializationBinder binder) (at :0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (System.Type objectType, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.SerializationBinder binder) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo memberObjectInfo) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at :0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (System.Object graph, System.Runtime.Remoting.Messaging.Header[] inHeaders, System.Runtime.Serialization.Formatters.Binary.__BinaryWriter serWriter, System.Boolean fCheck) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers, System.Boolean fCheck) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers) (at :0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph) (at :0) SaveSystem.Save () (at Assets/arena/Code/All_Mangers/SaveSystem.cs:146) GameControllerEditor.OnInspectorGUI () (at Assets/arena/Code/Editor/GameControllerEditor.cs:22) UnityEditor.UIElements.InspectorElement+<>c_DisplayClass58_0.b_0 () (at :0) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
public void Save()
{
hasSave = false;
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/playerInfo.data");
PlayerData data = new PlayerData();
data.playerLevel = playerLevel;
data.xp = xp;
data.xpToNextLevel = xpToNextLevel;
data.skillPoints = skillPoints;
hasGame = true;
data.hasGame = hasGame;
data.gold = gold;
data.drawSpeed = drawSpeed;
data.drawSpeedNumber = drawSpeedN;
data.AddHealth = AddHealth;
data.AddHealthN = AddHealthN;
data.drawSpeedDamage = drawSpeedDamage;
data.numberOfEnemys = numberOfEnemys;
data.mainWeaponID = mainWeaponID;
data.sideWeaponID = sideWeaponID;
data.helmetID = helmetID;
data.chestID = chestID;
data.arrowsID = arrowsID;
data.bootsID = bootsID;
data.gaunletsID = gaunletsID;
data.hasItem = hasItem;
data.arena = arena;
data.death = death;
data.main = main;
data.trainig = trainig;
data.Barracks = Barracks;
data.playerHeath = playerHeath;
data.addStamina = addStamina;
data.playerName = playerName;
data.items = items;
data.shopList = shopList;
// this the error when writing to file
bf.Serialize(file, data);
file.Close();
hasSave = true;
Debug.Log("saved player data");
}
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Binary Save on android issues 1 Answer
Help with Binary Save system 1 Answer
Multiple Cars not working 1 Answer
Problems with saving/loading score with PlayerPrefs [C#] 1 Answer