Saving ENUMs in C# and Loading it - c#

Im trying to save some enums in my code. Saving and converting to the string is going well. But with the loading there r some problems. I mean. I just cant load it). Im doing all that in unity. I thought to convert enum to string and after convert it back. Conversion to string works fine. But what happens with back-convestion i dont know. Thanks.
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class GameControl : MonoBehaviour {
public static GameControl control;
public float health;
public float experience;
public string stateString;
public enum State { start_0, start_1, start_3, start_4 };
public State myState;
void Awake () {
if(control == null)
{
DontDestroyOnLoad(gameObject);
control = this;
}
else if(control != this)
{
Destroy(gameObject);
}
}
public void Save()
{
stateString = myState.ToString(); //Converts ENUM to STRING
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath +
"/playerInfo.dat");
PlayerData data = new PlayerData();
data.health = health;
data.experience = experience;
data.stateString = stateString;
bf.Serialize(file, data);
file.Close();
}
public void Load()
{
if(File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
{
State loadedState = (State) Enum.Parse(typeof(State), stateString);
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath +
"/playerInfo.dat", FileMode.Open);
PlayerData data = (PlayerData)bf.Deserialize(file);
file.Close();
health = data.health;
experience = data.experience;
stateString = data.stateString;
}
}
}
[Serializable]
class PlayerData
{
public float health;
public float experience;
public string stateString;
public enum State { start_0, start_1, start_3, start_4 };
public State myState;
}

Related

Acces a mainclass from another classes using more constructors

I'm working in Unity to make a game and I'm having some problems with a Save System.
What I want is to save variables from more than 1 script.
In [GameManager.cs] i'm saving things like Level, Currency and Scores, all of that in one file.
In [MenuManager.cs] I want to save the user name IN ANOTHER file (in case he didn't did it yet) using the same saving system.
Acces those variables in other scripts. Example: I want to Log the variables saved in point 1) (GameManager.cs) in point 2) (MenuManager.cs). Or ... is possible to load(READ them from the saved file) them from [MenuManager.cs] using the same script from [GameManager.cs]? (I managed to load them only from [GameManager.cs] using the LoadPlayer() function).
Here is how 1st application run look like: https://imgur.com/a/IqoQjpX and the second: https://imgur.com/a/QpienFQ
The question is why in second photo it outputs blank? Why the save system works perfectly fine for [GameManager.cs] and for [MenuGame.cs] it doesn't?
Here s how the script looks:
[PlayerData]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public int Score;
public int BestScore;
public string UserName;
// 1st Constructor
public PlayerData(GameManager Player)
{
BestScore = Player.BestScore;
}
// 2nd Constructor
public PlayerData(MenuManager User)
{
UserName = User.UserName;
}
}
[SaveSystem.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public class SaveSystem
{
public static void SavePlayer(GameManager Player)
{
BinaryFormatter formatter = new BinaryFormatter();
string Path = Application.persistentDataPath + "/player.xd";
FileStream Stream = new FileStream(Path, FileMode.Create);
PlayerData Data = new PlayerData(Player);
formatter.Serialize(Stream, Data);
Stream.Close();
}
public static void SavePlayer(MenuManager Player)
{
BinaryFormatter formatter = new BinaryFormatter();
string Path = Application.persistentDataPath + "/name.xd";
FileStream Stream = new FileStream(Path, FileMode.Create);
PlayerData Data = new PlayerData(Player);
formatter.Serialize(Stream, Data);
Stream.Close();
}
public static PlayerData LoadPlayer()
{
string Path = Application.persistentDataPath + "/player.xd";
if (File.Exists(Path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream Stream = new FileStream(Path, FileMode.Open);
PlayerData Data = formatter.Deserialize(Stream) as PlayerData;
Stream.Close();
return Data;
}
else
{
return null;
}
}
public static PlayerData LoadName()
{
string Path = Application.persistentDataPath + "/name.xd";
if (File.Exists(Path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream Stream = new FileStream(Path, FileMode.Open);
PlayerData Data = formatter.Deserialize(Stream) as PlayerData;
Stream.Close();
return Data;
}
else
{
return null;
}
}
}
[MenuManager.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class MenuManager : MonoBehaviour
{
public string UserName = "whereIsTheLogic";
public InputField input;
public void Start()
{
// Here I checked if the user saved his name
PlayerData Data = SaveSystem.LoadName();
if (Data == null)
{
Debug.Log("User didn't saved his name");
/* so ... We jump to SaveButton() */
}
else
{
Debug.Log("User saved his name");
/* The file exists ... so we assume this isn't his first application use, right? */
/* Now what I want is to simply log the name ... just log already 4 god sake!! */
UserName = Data.UserName;
Debug.Log("User saved name is: " + UserName);
/* BUT it outputs blank NOT null or the inserted name) */
}
}
public void SaveButton()
{
string userName = input.text;
SaveSystem.SavePlayer(this);
Debug.Log("The user name: " + userName); /* yes ... it outputs the correct user answer */
}
public void PlayGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
[GameManager.cs] (only things that matter ...)
public class GameManager : MonoBehaviour
{
public int Score = 0;
public int BestScore = 0;
void Start()
{
/* Here I load saved variables (Score/Best Score)
and it loads them correctly
*/
LoadPlayer();
}
public void SavePlayer()
{
// Here I save the above mentioned variables and ... yes it works correctly
SaveSystem.SavePlayer(this);
Debug.Log("Salvat");
}
public void LoadPlayer()
{
PlayerData Data = SaveSystem.LoadPlayer();
Debug.Log("Loaded");
BestScore = Data.BestScore;
}
}
So the main issue comes from
string userName = input.text;
SaveSystem.SavePlayer(this);
Debug.Log("The user name: " + userName);
You make your Log dependend on the local variable userName, but you never update any field value of this (= MenuManager).
What you probably rather wanted would be updating the existing field UserName:
UserName = input.text;
SaveSystem.SavePlayer(this);
Debug.Log("The user name: " + UserName);
In general it is quite confusing to me that you have two separate files name.xd and player.xd, both storing serialized data for the same class PlayerData. And then each file only actually uses very specific fields of that class.
You should rather either have the two files but serialize actually the data you need or - what I would do - have one file serializing everything like
public class SaveSystem
{
private PlayerData _data = new PlayerData();
private string _path = Path.Combine(Application.persistentDataPath, "player.xd");
public static void SavePlayer(GameManager Player)
{
using(var stream = new File.Open(_path, FileMode.Create))
{
var formatter = new BinaryFormatter();
// instead of creating it new only update the field in the existing data
_data.BestScore = Player.BestScore;
formatter.Serialize(Stream, Data);
}
}
public static void SavePlayer(MenuManager Player)
{
using(var stream = new File.Open(_path, FileMode.Create))
{
var formatter = new BinaryFormatter();
// instead of creating it new only update the field in the existing data
_data.UserName = User.UserName;
formatter.Serialize(Stream, Data);
}
}
public static bool LoadPlayer(out PlayerData playerData)
{
playerData = default;
// Since you seem to anyway load only exactly ONCE per app start
// You could simply call this only ONCE
if(_data != null)
{
playerData = _data;
return true;
}
if (!File.Exists(path))
{
return false;
}
using(var stream = File.Open(path, FileMode.Open))
{
var formatter = new BinaryFormatter();
_data = formatter.Deserialize(Stream) as PlayerData;
}
playerData = _data;
return true;
}
}
and don't need the constructors so only
[System.Serializable]
public class PlayerData
{
public int Score;
public int BestScore;
public string UserName;
}
And you now would rather use e.g.
public class MenuManager : MonoBehaviour
{
public string UserName = "whereIsTheLogic";
public InputField input;
private void Start()
{
if(!SaveSystem.LoadPlayer(out var playerData))
{
Debug.Log("User didn't saved his name");
/* so ... We jump to SaveButton() */
}
else
{
Debug.Log("User saved his name");
UserName = playerData.UserName;
Debug.Log("User saved name is: " + UserName);
}
}
public void SaveButton()
{
UserName = input.text;
SaveSystem.SavePlayer(this);
Debug.Log("The user name: " + UserName);
}
public void PlayGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
and accordingly
public class GameManager : MonoBehaviour
{
public int Score = 0;
public int BestScore = 0;
void Start()
{
LoadPlayer();
}
public void SavePlayer()
{
SaveSystem.SavePlayer(this);
Debug.Log("Salvat");
}
public void LoadPlayer()
{
if(SaveSystem.LoadPlayer(out var playerData))
{
Debug.Log("Loaded");
BestScore = playerData.BestScore;
}
}
}
You are right about the local variable :) Looked in your script a while, I managed to fix the errors (probably cause we have different compilers)
but the saving system doesn't work with your method. Thanks for your time and help but I think your script is a bit way too much for me (at least for now).
The things I had to change to your code to be able to compile the program: https://pastebin.com/umHpLJmL
I managed to save both score and name in one single file but with a non religious method.
Even if my game isn't about optimizing or things like that, I still want to get better results and to improve my knowledge.
So, down below I made the following modifications:
[SaveSystem.cs]
public class SaveSystem
{
static string Path = Application.persistentDataPath + "/Save";
public static void SavePlayer(GameManager Player)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream Stream = new FileStream(Path, FileMode.Create);
// FileStream Stream = File.Open(Path, FileMode.Open);
PlayerData Data = new PlayerData(Player);
formatter.Serialize(Stream, Data);
Stream.Close();
}
public static void SavePlayer(MenuManager Player)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream Stream = new FileStream(Path, FileMode.Create);
// FileStream Stream = File.Open(Path, FileMode.Open);
PlayerData Data = new PlayerData(Player);
formatter.Serialize(Stream, Data);
Stream.Close();
}
public static PlayerData LoadPlayer()
{
if (File.Exists(Path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream Stream = new FileStream(Path, FileMode.Open);
PlayerData Data = formatter.Deserialize(Stream) as PlayerData;
Stream.Close();
return Data;
}
else
{
return null;
}
}
}
[GameManager.cs]
And here's the thing: in order not to lose any variables while saving the score, I made a load just before the new saving and then I saved the username in a global GameManager variable.
So now I can easily save the game and after restarting it both name and score are saved.
public void SavePlayer()
{
PlayerData Data = SaveSystem.LoadPlayer();
UserName = Data.UserName;
SaveSystem.SavePlayer(this);
Debug.Log("Salvat " + Data.UserName);
}
public void LoadPlayer()
{
PlayerData Data = SaveSystem.LoadPlayer();
Debug.Log("Loaded");
BestScore = Data.BestScore;
}
[PlayerData.cs]
[System.Serializable]
public class PlayerData
{
public int Score;
public int BestScore;
public string UserName;
public PlayerData(GameManager Player)
{
BestScore = Player.BestScore;
UserName = Player.UserName;
}
public PlayerData(MenuManager Player)
{
UserName = Player.UserName;
}
}
So my question is, how can I do it JUST better? I mean, isn't there an option to save things in file in a specific section and not to modify the other things which are in the file?
Example:
[Level="18"]
[Name="Andrei"]
And to be able to modify only the parameter I choose to.
Another solution which came in my mind is (don't know if is possible to implement, just asking):
public static void SavePlayer(GameManager obj1, MenuManager obj2)
{
// Loading both global scene variables
PlayerData _data1 = new PlayerData(obj1);
PlayerData _data2 = new PlayerData(obj2);
// Copying the variables into global SaveSystem variables
Score = _data1.Score;
UserName = _data2.UserName;
// Saving global SaveSystem variables into document
formatter.Serialize(Stream, this);
}
There are two problems:
Calling the function: SaveSystem.SavePlayer(GameManager, MenuManager);
I used to make the calls with this. With what should I replace it? Isn't it a refference to current class name?
formatter.Serialize(Stream, this);
What I want in point 2) is to save the global class variables into document. But how? Using this doesn't make the refference to the class.

How can I add the locksystem state to my SaveState class?

The Lock System script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LockSystem : MonoBehaviour
{
public bool mouseCursorLockState = true;
public PlayerCameraController playerCameraController;
public PlayerController playerController;
// Start is called before the first frame update
void Start()
{
MouseCursorLockState(mouseCursorLockState);
}
public void MouseCursorLockState(bool lockState)
{
if (lockState == false)
{
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
else
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
public void PlayerLockState(bool LockPlayer, bool LockPlayerCamera)
{
if (LockPlayer == true)
{
playerController.enabled = false;
}
else
{
playerController.enabled = true;
}
if (LockPlayerCamera == true)
{
playerCameraController.enabled = false;
}
else
{
playerCameraController.enabled = true;
}
}
}
I'm using it in some places in my game for example :
public LockSystem playerLockMode;
playerLockMode.PlayerLockState(true, false);
The playerLockMode is at the top and the using it in some function it's just exmaple of how I'm using it.
The Save State class. So far I can save any object position rotation scaling. Now I want to save also the locking system state :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[Serializable]
public class SaveState
{
[Serializable]
public struct SerializableVector3
{
public float X;
public float Y;
public float Z;
public SerializableVector3(Vector3 v)
{
X = v.x;
Y = v.y;
Z = v.z;
}
// And now some magic
public static implicit operator SerializableVector3(Vector3 v)
{
return new SerializableVector3(v);
}
public static implicit operator Vector3(SerializableVector3 sv)
{
return new Vector3(sv.X, sv.Y, sv.Z);
}
}
[Serializable]
public struct SerializableQuaternion
{
public float X;
public float Y;
public float Z;
public float W;
public SerializableQuaternion(Quaternion q)
{
X = q.x;
Y = q.y;
Z = q.z;
W = q.w;
}
public static implicit operator SerializableQuaternion(Quaternion q)
{
return new SerializableQuaternion(q);
}
public static implicit operator Quaternion(SerializableQuaternion sq)
{
return new Quaternion(sq.X, sq.Y, sq.Z, sq.W);
}
}
public SerializableVector3 position;
public SerializableQuaternion rotation;
public SerializableVector3 scale;
public SaveState(Vector3 pos, Quaternion rot, Vector3 sca)
{
position = pos;
rotation = rot;
scale = sca;
}
public void ApplyToPlayer(Transform player)
{
player.localPosition = position;
player.localRotation = rotation;
player.localScale = scale;
}
public bool LockState(bool lockState)
{
return lockState;
}
}
I tried to add in the bottom the new function LockState but that's not the right way to handle it.
The save manager script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System;
using System.IO;
public class SaveManager : MonoBehaviour
{
public static void Save(SaveState player)
{
BinaryFormatter formatter = new BinaryFormatter();
string path = Application.persistentDataPath + "/player.bin";
FileStream stream = new FileStream(path, FileMode.Create);
formatter.Serialize(stream, player);
stream.Close();
}
public static SaveState Load()
{
string path = Application.persistentDataPath + "/player.bin";
if (File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(path, FileMode.Open);
SaveState data = formatter.Deserialize(stream) as SaveState;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not found in " + path);
return null;
}
}
}
The Player State script for saving the player state but I can also save here the lock system state just not sure yet how :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerState : MonoBehaviour
{
private void Awake()
{
Save();
}
public void Save()
{
SaveState saveState = new SaveState(transform.localPosition,
transform.localRotation, transform.localScale);
SaveManager.Save(saveState);
}
public void Load()
{
var playerInfo = SaveManager.Load();
playerInfo.ApplyToPlayer(transform);
}
}
Once the game start I'm saving in the Awake once.
Then calling the Load function to my Main Menu ui button :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainMenu : MonoBehaviour
{
public void StartNewGame()
{
ScenesManager.StartNewGame();
}
public void LoadGame()
{
var playerstate = GameObject.Find("Player").GetComponent<PlayerState>();
playerstate.Load();
}
public void ResumeGame()
{
ScenesManager.ResumeGame();
}
public void QuitGame()
{
Application.Quit();
}
}
My idea is to save one the game start and then using a timer and save each 5 minutes for example.
So I'm calling only the Load function in the Main Menu. The save will be automatic during the game.
In the SaveState class I want to add more and more stuff to save it's state like the locking system and also a coroutine state. The game start with a running coroutine that make some effect. I want also to save the coroutine state if the game save at the start or a bit later while the coroutine is running so save the current coroutine state too.
This is when the game start :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PostProcessing;
public class DepthOfField : MonoBehaviour
{
public UnityEngine.GameObject player;
public PostProcessingProfile postProcessingProfile;
public bool dephOfFieldFinished = false;
public LockSystem playerLockMode;
private Animator playerAnimator;
private float clipLength;
private Coroutine depthOfFieldRoutineRef;
// Start is called before the first frame update
void Start()
{
if (depthOfFieldRoutineRef != null)
{
StopCoroutine(depthOfFieldRoutineRef);
}
playerAnimator = player.GetComponent<Animator>();
AnimationClip[] clips = playerAnimator.runtimeAnimatorController.animationClips;
foreach (AnimationClip clip in clips)
{
clipLength = clip.length;
}
DepthOfFieldInit(clipLength);
// Don't forget to set depthOfFieldRoutineRef to null again at the end of routine!
}
public void DepthOfFieldInit(float duration)
{
var depthOfField = postProcessingProfile.depthOfField.settings;
depthOfField.focalLength = 300;
StartCoroutine(changeValueOverTime(depthOfField.focalLength, 1, duration));
postProcessingProfile.depthOfField.settings = depthOfField;
}
public IEnumerator changeValueOverTime(float fromVal, float toVal, float duration)
{
playerLockMode.PlayerLockState(true, true);
float counter = 0f;
while (counter < duration)
{
var dof = postProcessingProfile.depthOfField.settings;
counter += Time.deltaTime;
float val = Mathf.Lerp(fromVal, toVal, counter / duration);
dof.focalLength = val;
postProcessingProfile.depthOfField.settings = dof;
yield return null;
}
playerAnimator.enabled = false;
dephOfFieldFinished = true;
depthOfFieldRoutineRef = null;
}
}
This is a screenshot of the game start and the effect while the coroutine is running :
This blur effect is made by the PostProcessing and the coroutine.
I want also to save the state if that.
Saving objects info is easy like position rotation and scaling but how can I save the state of other stuff like the locking system and the DepthOfField ? How should I extend the SaveState class and then how to use it to save it in the PlayerState script ?

Loading game does not load the position of the player

I've been trying to implement a savegame function into my game. When I load the game from the save, it doesn't load the position of the player.
I have 2 main scenes: The scene in which the game is taking place, and the main menu scene. The main menu makes use of my load function, which is supposed to read my save file and put the player at a given position, however, it just loads the scene at the default position. No errors are thrown, no warning messages. Here is all of my code:
This is my Save game system:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveSystem
{
public static void SavePlayer (Player player)
{
BinaryFormatter formatter = new BinaryFormatter();
string path = Application.persistentDataPath + "player.fun";
FileStream stream = new FileStream(path, FileMode.Create);
PlayerData data = new PlayerData(player);
formatter.Serialize(stream, data);
stream.Close();
}
public static PlayerData LoadPlayer ()
{
string path = Application.persistentDataPath + "/player.fun";
if (File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(path, FileMode.Open);
PlayerData data = formatter.Deserialize(stream) as PlayerData;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not in " + path);
return null;
}
}
}
Container for player data:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public int level;
public int health;
public float[] position;
public int stamina;
public PlayerData (Player player)
{
level = player.level;
health = player.health;
stamina = player.stamina;
position = new float[3];
position[0] = player.transform.position.x;
position[1] = player.transform.position.y;
position[2] = player.transform.position.z;
}
}
My Scene Changing Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneChanger : MonoBehaviour
{
public static bool Isload = false;
public void gotoWelwardLoad()
{
SceneManager.LoadScene("Welward");
bool Isload = true;
}
public void gotoWelward()
{
SceneManager.LoadScene("Welward");
}
public void gotomainmenu()
{
SceneManager.LoadScene("Menu");
}
}
My Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
public int health = 1;
public int stamina = 1;
public int level = 1;
public void SavePlayer ()
{
SaveSystem.SavePlayer(this);
}
public void LoadPlayer ()
{
SceneManager.LoadScene("Welward");
PlayerData data = SaveSystem.LoadPlayer();
level = data.level;
health = data.health;
stamina = data.stamina;
Vector3 position;
position.x = data.position[0];
position.y = data.position[1];
position.z = data.position[2];
transform.position = position;
}
public static void gotomenu ()
{
SceneManager.LoadScene("Menu");
}
public static void Welward()
{
SceneManager.LoadScene("Welward");
SaveSystem.LoadPlayer();
}
}
Link with full unity project files:
https://drive.google.com/open?id=1mFH5aNklC0qMWeJjMT4KD0CbTTx65VRp
As BugFinder correctly points out, your save path is different than your loading path.
Try changing Application.persistentDataPath + "player.fun"; to Application.persistentDataPath + "/player.fun"; to match your loading code. Or you could move that string path variable up into the class as a const then reference it since it will be guaranteed to match.
After that however you will also need to call Player.LoadPlayer() somewhere since in your existing project you do not do that anywhere I can find, and when you call it currently it will reload the scene (which probably isn't the behaviour you want either). I would remove SceneManager.LoadScene("Welward"); from that method.
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public static class SaveSystem
{
// This is a way to make sure your path is the same, and not about to get overwritten
public static string Path => Application.persistentDataPath + "/player.fun";
public static void SavePlayer (Player player)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Path, FileMode.Create);
PlayerData data = new PlayerData(player);
formatter.Serialize(stream, data);
stream.Close();
// It's helpful to print out where this is going
Debug.Log($"Wrote to {Path}");
}
public static PlayerData LoadPlayer ()
{
if (File.Exists(Path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(Path, FileMode.Open);
PlayerData data = formatter.Deserialize(stream) as PlayerData;
stream.Close();
// It's also helpful to print out that it worked, not just log errors if it fails
Debug.Log($"Successfully read from {Path}");
return data;
}
else
{
Debug.LogError("Save file not in " + Path);
return null;
}
}
}
One thing thats noticeable is in save you use Application.persistentDataPath + "player.fun"; and in load you use, Application.persistentDataPath + "/player.fun"; So, perhaps therefore it doesnt find the file to load it. As you thought. Personally Path.Combine is a good option, platform non specific etc. So try replacing both with Path.Combine(Application.persistentDataPath,"player.fun");
From the code you provided I don't see the part where you call Player.LoadPlayer(). So add it to Player:
void Start(){
LoadPlayer();
}
Hope it helps.

Working on a blackjack style unity game. Can't read and write a file

So. I'm trying to make a save profile but I have the error shown in the picture and have no idea how to fix it as I have been following tutorials on YouTube and this error never occurred. Can anyone help me work out what I should do.
using UnityEngine;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class SavingControl : MonoBehaviour
{
public static SavingControl control;
public int cash = PlayerBetting.instance.bankBal;
public int difficulty = 2;
void Awake ()
{
if (control = null)
{
DontDestroyOnLoad(gameObject);
control = this;
}
else if (control != this)
{
Destroy(gameObject);
}
}
public void Save()
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/playerInfo.dat");
PlayerData data = new PlayerData();
data.BankBal = cash;
data.Difficulty = difficulty;
bf.Serialize(file, data);
file.Close();
}
public void Load()
{
if (File.Exists(Application.persistentDataPath + "/PlayerInfo.dat"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath = "/PlayerInfro.dat", FileMode.Open);
PlayerData data = (PlayerData)bf.Deserialize(file);
file.Close();
cash = data.BankBal;
difficulty = data.Difficulty;
}
}
}
[Serializable]
class PlayerData
{
public int BankBal;
public int Difficulty;
}
Change the = to a +:
FileStream file = File.Open(Application.persistentDataPath + "/PlayerInfro.dat", FileMode.Open);
Better yet use Path.Combine:
FileStream file = File.Open(Path.Combine(Application.persistentDataPath, "PlayerInfro.dat"), FileMode.Open);

C# Unity Serialized Hashtable never get´s Assigned

Im working on a Game. I have a ProgressControl Class that tracks the Players Progress, and save and load that to a Binary File. Serializing Gold and Points works. Now I want to add a Hashtable to save the Points for every Level, to Limit the maximum Points a Player can get on every Level. But the Hashtable in the Serializable Class never gets assigned and stays null. So no Points are saved.
How can I get that Hashtable serialized? What am I missing?
using UnityEngine;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections;
public class ProgressControl : MonoBehaviour
{
public static ProgressControl progress;
public int gold;
public int points;
public int level;
public Hashtable h;
void Awake()
{
h = new Hashtable();
if (progress == null)
{
DontDestroyOnLoad(gameObject);
progress = this;
}
else if (progress != this)
{
Destroy(gameObject);
}
}
public void save()
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/playerInfo.dat");
PlayerData data = new PlayerData();
data.gold = gold;
data.points = points;
data.h = h;
bf.Serialize(file, data);
file.Close();
}
public void load()
{
if (File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
PlayerData data = (PlayerData)bf.Deserialize(file);
file.Close();
gold = data.gold;
points = data.points;
h = data.h;
}
}
public void saveLevel()
{
level = TargetScript.activeLevel;
Debug.Log("Level Saved");
}
public void savePointsToHashMap(int LevelKey, int points)
{
if (h.ContainsKey(LevelKey))
{
object value = h[LevelKey];
int compare = int.Parse(value.ToString());
if (compare < points)
{
h.Add(LevelKey, points);
Debug.Log("Overwrite and Save Points");
}
}
else{
Debug.Log("Save Points");
h.Add(LevelKey, points);
}
save();
}
}
[Serializable]
class PlayerData
{
public int gold;
public int points;
public Hashtable h;
}

Categories

Resources