1

I'm currently encountering an error in a large scale project.

Code below:

public void SaveFileExists(){

    Debug.Log ("SaveFileExists was called.");

    //GameObject.Find ("_Scripts").GetComponent<SaveGame> ().Load ();
    UserData userdata = null;

    //Creating a new BinaryFormatter
    BinaryFormatter bf = new BinaryFormatter ();

    //Making a file which now contains the Un-Serialized File
    FileStream file = File.Open (Application.persistentDataPath + ("/UserData." + accountLoginAttempt), FileMode.Open);

    //Assigning the values of the saved file to the new file
    //UserData newData = (UserData)bf.Deserialize (file);

    userdata = bf.Deserialize(file) as UserData;

    //Assigning the values from the save file to the variables in this script.
    accountLoginAttempt = userdata.username;
    accountLevel = userdata.userlevel;

    //Assinging the values from this script to the _PlayerManager script. (This is where the UI gets it's info).
    GameObject.Find ("_AccountInfoSaveHolder").GetComponent<HoldInfo> ().UserInfo = accountLoginAttempt;
    GameObject.Find ("_AccountInfoSaveHolder").GetComponent<HoldInfo> ().UserLevel = accountLevel;

    errortext.text = "Login Successful.";
    Canvas.ForceUpdateCanvases ();
}

The serialised field is also below:

[System.Serializable]
class UserData{
public string username;
public int userlevel;
}

I am trying to load a savefile which is stored in the Application.persistentDataPath. Assigning the UserData.username and UserData.userlevel to variables in my script.

The error I am receiving is:

InvalidCastException: Cannot cast from source type to destination type.

Further Details:

LoginScript.SaveFileExists () (at Assets/Scripts/AccountSystem/LoginScript.cs:126) LoginScript.OnLoginClick () (at Assets/Scripts/AccountSystem/LoginScript.cs:104) UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:153) UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:634) UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:769) UnityEngine.Events.UnityEvent.Invoke () (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:53) UnityEngine.UI.Button.Press () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35) UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44) UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52) UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269) UnityEngine.EventSystems.EventSystem:Update()

EDIT:

SaveGame.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary; 
using System.IO;
using UnityEngine.SceneManagement;

public class SaveGame : MonoBehaviour {

//Saved Variables
[Header("Saved Variables")]
public string savedname;
public string attemptedlogin;
public int savedlevel;

//Loaded Variables
[Header("Loaded Variables")]
public string loadedname;
public int loadedlevel;


public void Awake(){

    if (SceneManager.GetActiveScene ().name == "GameScene") {
        Load ();
    }
}

public void Save(){

    savedname = GameObject.Find ("_Scripts").GetComponent<PlayerManager> ().PlayerName;
    savedlevel = GameObject.Find ("_Scripts").GetComponent<PlayerManager> ().UserLevel;

    BinaryFormatter bf = new BinaryFormatter();

    FileStream file = File.Open(Application.persistentDataPath + ("/UserData." + savedname), FileMode.Create);

    UserData newData = new UserData();

    newData.username = savedname;
    newData.userlevel = savedlevel;

    bf.Serialize(file, newData);
    file.Close();
}
}

I also removed all System.Serializable class's throughout my scripts and made a script called UserDataSerialize.cs which contains:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
class UserData{
    public string username;
    public int userlevel;
}

Now the error I get is:

TypeLoadException: Could not load type 'SaveGame+UserData'.
System.Reflection.Assembly.GetType (System.String name, Boolean throwOnError, Boolean ignoreCase) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/Assembly.cs:398)
System.Reflection.Assembly.GetType (System.String name, Boolean throwOnError) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/Assembly.cs:381)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:833)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:637)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectInstance (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:269)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:195)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:223)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (BinaryElement element, System.IO.BinaryReader reader) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:130)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:104)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:179)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:136)
LoginScript.SaveFileExists () (at Assets/Scripts/AccountSystem/LoginScript.cs:111)
LoginScript.OnLoginClick () (at Assets/Scripts/AccountSystem/LoginScript.cs:84)
UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:153)
UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:634)
UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent.cs:769)
UnityEngine.Events.UnityEvent.Invoke () (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:53)
UnityEngine.UI.Button.Press () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44)
UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52)
UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269)
UnityEngine.EventSystems.EventSystem:Update()
halfer
  • 19,824
  • 17
  • 99
  • 186
Valkarth
  • 59
  • 1
  • 8
  • The only explicit cast is the result of `BinaryFormatter.Deserialize` to type `UserData`. Are you sure the file is in the format you expect? – Andy Lamb Jun 20 '17 at 05:55
  • @AndyLamb I think so? What exactly do you mean by the format it is expected. The class 'UserData' is a string 'username' followed by an int 'userlevel'. – Valkarth Jun 20 '17 at 06:08
  • What is your Unity version? Can you also put your save code in your question? – Programmer Jun 20 '17 at 06:08
  • Unity 5.5.1f1 Personal (64bit) on Mac. SaveGame.cs: public void InitializeSave(){ savedname = GameObject.Find ("_Scripts").GetComponent ().PlayerName; savedlevel = GameObject.Find ("_Scripts").GetComponent ().UserLevel; Save (); } MORE CODE IN NEXT COMMENT – Valkarth Jun 20 '17 at 06:10
  • Part 2 public void Save(){ BinaryFormatter bf = new BinaryFormatter(); //Creates a new file at the directory of the save path. FileStream file = File.Open(Application.persistentDataPath + ("/UserData." + savedname), FileMode.Create); //Clearing temp files and starting from a new file UserData newData = new UserData(); //Assigning Variables newData.username = savedname; newData.userlevel = savedlevel; //Encodes newData to file. bf.Serialize(file, newData); file.Close(); } – Valkarth Jun 20 '17 at 06:13
  • The code looks fine and works with 5.6. Can you post your save code? You only have read/load code in your question. By the way, you edit and post the code in your question. Just add Edit to it then paste the code there not in the comment section. – Programmer Jun 20 '17 at 06:14
  • Sweet, i'll do it now thanks :) – Valkarth Jun 20 '17 at 06:19
  • I also tried removing all serialized fields I had in other scripts and just made another script called UserDataSerialization.cs which is just: using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] class UserData{ public string username; public int userlevel; } – Valkarth Jun 20 '17 at 06:25
  • Before I make further comments please note that I advice people to stay away from `BinaryFormatter` and instead use [Json](https://stackoverflow.com/a/40966346/3785314). I've had bad experience with `BinaryFormatter` too and this problem is found in Unity only. – Programmer Jun 20 '17 at 06:28
  • I honestly agree with you but this project is due in just 2 days so I really wouldn't be comfortable in re-creating the saving/loading system. p.s i've checked out your profile ;) – Valkarth Jun 20 '17 at 06:30
  • There is a post I linked above. That's a workaround and it takes minutes to use that if you read it. You will use that if we can't solve the problem. – Programmer Jun 20 '17 at 06:31
  • The paths are not the-same. Please verify that. You saved to `Application.persistentDataPath + ("/UserData." + savedname)` **but** you are reading from `Application.persistentDataPath + ("/UserData." + accountLoginAttempt)`. Does that ring a bell? – Programmer Jun 20 '17 at 06:32
  • Sure thing, I just want to have a go at the BinaryFormatter since it's the only problem in my large project so it will greatly reduce the workload. – Valkarth Jun 20 '17 at 06:33
  • I am pretty sure that they are the same thing because i've declared them to be the same but i'll just check again. I'll just write a Debug.Log of both paths. – Valkarth Jun 20 '17 at 06:35
  • Make it global variable called `path` then log it with `Debug.Log("Read from to: " + path.Replace("/", "\\"));` in both save and load function. Copy the path from the log and paste both of them to the windows search bar then open them. It will show you if they are the-same. – Programmer Jun 20 '17 at 06:39
  • Ok, all paths are the same, they are just under different variable names due to the different scripts. – Valkarth Jun 20 '17 at 06:42
  • Ok. Use [this](https://codeshare.io/G8JR7e) to save the file. Use your read code to read it just after saving it. – Programmer Jun 20 '17 at 06:45
  • I fixed it!!! I was just searching through some code and discovered that [accountLoginAttempt = userdata.username;] should actually be [accountLoginAttempt = newData.username;]. I also changed the 3 following lines to that same adaptation. – Valkarth Jun 20 '17 at 06:47
  • Thanks heaps for the help @Programmer :) Is there anything I can do to upvote your profile ahah? – Valkarth Jun 20 '17 at 06:48
  • You can't upvote until you have 15 rep. You have 6 now. **Don't** upvote unless I leave an answer but I didn't. What fixed it? You can answer your own question if you fixed it to help other people that will run into your problem in the future. – Programmer Jun 20 '17 at 06:49
  • Just cleaning up code and adding Debug.Log functions through every major step and seeing where the problem was. It also came up with a NullException so I knew it had to do with the assignment of variables. Therefore, it had to be the step after the Deserialization. – Valkarth Jun 20 '17 at 06:53
  • I fixed the Deserialization by making that third script which only had the System.Serialize class. – Valkarth Jun 20 '17 at 06:54

2 Answers2

1

Solution:

Create another script which only contains:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
class UserData{
    public string username;
    public int userlevel;
}

And delete all other System.Serialize class's of the same name throughout other scripts.

Valkarth
  • 59
  • 1
  • 8
0

Maybe not a problem for everyone, but this helped me: In the course of building my save structure, I first saved one type of object, but then switched to a different one. My game was set to load before there was an opportunity to save, and so I was loading an old class without having saved over it with the new class. I was able to resolve the problem by disabling load, playing the game for a turn, saving, and then turning load on again.

Truth
  • 486
  • 7
  • 19