Jump to content
Auronity

Como serializar int y string?

Recommended Posts

Hola, estoy guardando la posición de una instancia con Json y quiero saber si puedo guardar en el mismo archivo un int (color: que con un switch cambia el color del objeto) y un string (nombre). En caso de que no pueda, ¿como podría hacerlo?

Acabo de hacer una prueba solo con el string y esto es lo que se guarda:

 

Share this post


Link to post
Share on other sites

Veo que estás complicando muchísimo con esto, estuve intentando armar algo que simplifique el guardado y carga de información --- Esto lo hace de manera automática sin tener que romperte la cabeza.

using System;
using System.Reflection;
using System.Text;
using UnityEngine;

public static class GameData
{
    public static void InternalWriter(Type type, string key, string val)
    {
        PlayerPrefs.SetString(type + key, val);
    }

    private static string InternalReader(string key)
    {
        return PlayerPrefs.GetString(key);
    }

    public static void Write<T>(string key, T obj)
    {
        InternalWriter(typeof(T), key, obj.ToString());
    }

    public static T Read<T>(string key)
    {
        try
        {
            return (T)((object)InternalReader(typeof(T) + key));
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
        }

        return default(T);
    }

    private static void Write(string key, DataBehaviour val)
    {
        Writer writer = new Writer();
        val.Serialize(writer);
        InternalWriter(val.GetType(), key, writer.GetString());
    }

    public partial class Reader
    {
        public Reader(byte[] bytes)
        {
            data = Encoding.UTF8.GetString(bytes).Split('\\');
        }

        public int CurrentPosition { get { return position; } }

        private int position = ;
        private string[] data;

        public bool IsReadAll()
        {
            return data.Length == position;
        }

        public int ReadInt()
        {
            try
            {
                var r = int.Parse(data[position++]);
                return r;
            }
            catch
            {
                return ;
            }
        }

        public float ReadFloat()
        {
            try
            {
                var r = float.Parse(data[position++]);
                return r;
            }
            catch
            {
                return ;
            }
        }

        public string ReadString()
        {
            try
            {
                var r = data[position++];
                return r;
            }
            catch
            {
                return string.Empty;
            }
        }

        public char ReadChar()
        {
            try
            {
                var r = char.Parse(data[position++]);
                return r;
            }
            catch
            {
                return new char();
            }
        }

        public short ReadShort()
        {
            try
            {
                var r = short.Parse(data[position++]);
                return r;
            }
            catch
            {
                return ;
            }
        }

        public bool ReadBool()
        {
            try
            {
                var r = int.Parse(data[position++]) == 1;
                return r;
            }
            catch
            {
                return false;
            }
        }

        public Vector3 ReadVector3()
        {
            try
            {
                return new Vector3().Parse(data[position++]);
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);

                return Vector3.zero;
            }
        }       

        public void ReadTransform(Transform transform)
        {
            if (transform == null) return;

            string[] vars = ReadString().Split(':');
            transform.name = vars[];
            transform.position = new Vector3().Parse(vars[1]);
            transform.localScale = new Vector3().Parse(vars[2]);
            transform.rotation = Quaternion.Euler(new Vector3().Parse(vars[3]));
        }
    }

    public partial class Writer
    {
        private StringBuilder data = new StringBuilder();

        public void Write(int value)
        {
            Append(value);
        }

        public void Write(float value)
        {
            Append(value);
        }

        public void Write(string value)
        {
            Append(value);
        }

        public void Write(char value)
        {
            Append(value);
        }

        public void Write(bool value)
        {
            Append((value) ? 1 : );
        }

        public void Write(short value)
        {
            Append(value);
        }

        public void Write(Vector3 value)
        {
            Append(string.Format("{0},{1},{2}", value.x, value.y, value.z));
        }

        public void Write(Transform value)
        {
            if (value == null) return;
            Append(string.Format("{0}:{1}:{2}:{3}",
                value.name.Replace(":", ""),
                value.position.Serialize(),
                value.localScale.Serialize(),
                value.rotation.eulerAngles.Serialize()));
        }

        private void Append(object value)
        {
            var str = value.ToString().Replace("\r", "").Replace("\f", "").Replace("\n", "").Replace("\\", "");
            data.AppendFormat("{0}\\", str);
        }

        public byte[] GetBytes()
        {
            return Encoding.UTF8.GetBytes(GetString ());
        }

        public string GetString()
        {
            return data.ToString();
        }
    }

    public partial class DataBehaviour : MonoBehaviour
    {
        private const BindingFlags FLAGS = (
            BindingFlags.Instance |
            BindingFlags.Public |
            BindingFlags.NonPublic |
            BindingFlags.GetProperty |
            BindingFlags.SetProperty);

        internal void Serialize(Writer writer)
        {
            writer.Write(transform);
            OnSerialize(writer);
        }

        internal void Deserialize(Reader reader)
        {
            reader.ReadTransform(transform);
            OnDeserialize(reader);
        }

        public virtual void OnSerialize(Writer writer)
        {
            FieldInfo[] fields = GetType().GetFields(FLAGS);

            foreach (var field in fields)
            {
                if (field.FieldType == typeof(int)) writer.Write((int)field.GetValue(this));

                if (field.FieldType == typeof(string)) writer.Write((string)field.GetValue(this));

                if (field.FieldType == typeof(bool)) writer.Write((bool)field.GetValue(this));

                if (field.FieldType == typeof(float)) writer.Write((float)field.GetValue(this));

                if (field.FieldType == typeof(short)) writer.Write((short)field.GetValue(this));

                if (field.FieldType == typeof(char)) writer.Write((char)field.GetValue(this));

                if (field.FieldType == typeof(Vector3)) writer.Write((Vector3)field.GetValue(this));

                if (field.FieldType == typeof(Vector2)) writer.Write((Vector3)field.GetValue(this));

                if (field.FieldType == typeof(Quaternion)) writer.Write(((Quaternion)field.GetValue(this)).eulerAngles);

                if (field.FieldType == typeof(Transform)) writer.Write((Transform)field.GetValue(this));
            }
        }

        public virtual void OnDeserialize(Reader reader)
        {
            FieldInfo[] fields = GetType().GetFields(FLAGS);

            foreach (var field in fields)
            {
                if (field.FieldType == typeof(int)) field.SetValue(this, reader.ReadInt());

                if (field.FieldType == typeof(string)) field.SetValue(this, reader.ReadString());

                if (field.FieldType == typeof(bool)) field.SetValue(this, reader.ReadBool());

                if (field.FieldType == typeof(float)) field.SetValue(this, reader.ReadFloat());

                if (field.FieldType == typeof(short)) field.SetValue(this, reader.ReadShort());

                if (field.FieldType == typeof(char)) field.SetValue(this, reader.ReadChar());

                if (field.FieldType == typeof(Vector3)) field.SetValue(this, reader.ReadVector3());

                if (field.FieldType == typeof(Vector2)) field.SetValue(this, reader.ReadVector3());

                if (field.FieldType == typeof(Quaternion)) field.SetValue(this, Quaternion.Euler(reader.ReadVector3()));

                if (field.FieldType == typeof(Transform)) reader.ReadTransform((Transform)field.GetValue(this));
            }
        }

        public void Save(string key)
        {
            Write(key, this);
        }

        public void Load(string key)
        {
            Reader reader = new Reader(Encoding.UTF8.GetBytes(InternalReader(GetType() + key)));
            Deserialize(reader);
        }
    }    
}

internal static class Vertor3Ext
{
    internal static Vector3 Parse(this Vector3 vec, string data)
    {
        string[] vars = data.Split(',');
        vec.x = float.Parse(vars[]);
        vec.y = float.Parse(vars[1]);
        vec.z = (vars.Length > 2) ? float.Parse(vars[2]) : ;
        return vec;
    }

    internal static string Serialize(this Vector3 vec)
    {
        return string.Format("{0},{1},{2}", vec.x, vec.y, vec.z);
    }
}

Para utilizarlo deberias usar la clase DataBehaviour 

public class Test : GameData.DataBehaviour
{
    public int Valor = 1;
    public Transform Cam;
    public Vector3 Datos2;

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.G))
        {
            Save("MiObject1");
        }

        if(Input.GetKeyDown(KeyCode.E))
        {
            Load("MiObject1");
        }
    }
}

Utilizar la función Save(Llave con la que vas a guardar) y se guardan los datos ...

Utilizar la función Load(Llave utilizada anteriormente)  y se cargan los dato..

Los datos admitidos son

int, float, short, char, string, bool, Vector3, Vector2, Quaternion,Transform, pero puedes modificarlo a gusto agregar lo que necesites.

Internamente trabaja con PlayerPrefs pero tranquilamente podes reescribir internalWriter para poder utilizar la forma de salida que requieras como grabar un XML TXT o lo que necesites.

Share this post


Link to post
Share on other sites

Lo intente de la siguiente manera:

 

[System.Serializable]
	public class dataPCN {

		private string pos, col, nom;

		public dataPCN(Vector3 posicion,int color, string nombre) {
			pos = JsonUtility.ToJson(posicion);
			nom = JsonUtility.ToJson(nombre);
			col = JsonUtility.ToJson(color);
		}

		public Vector3 posicion() {
			return JsonUtility.FromJson<Vector3> (pos);
		}

		public int color() {
			return JsonUtility.FromJson<int> (col);
		}

		public string nombre() {
			return JsonUtility.FromJson<string> (nom);
		}
	}

Pero cuando guardo y abro el archivo que se crea, solo aparece la posición:

    ÿÿÿÿ         Assembly-CSharp   SaveLoadM+dataPCN   pos     F{"x":-114.04374694824219,"y":-50.51359558105469,"z":515.8074340820313}         { }    { } <-- En estas dos llaves debería ir el int y el string pero

siempre aparecen vacías. Por eso creo que el int y el string no se convierten a Json así. Y aunque he estado horas buscando nunca encuentro nada que me ayude a ver como funciona realmente la serialización

Lightbug, en caso de que mi script este mal, sabes como podría integrar el script del link que me has pasado? Tendria que crear una clase serializable fuera del "dataPCN"?

Un saludo

Edited by Auronity

Share this post


Link to post
Share on other sites

Yo lo veo algo asi, esto es muy básico de Json pero debería funcionar, lo que hace es que todos tus datos los tenes dentro de la clase JSONData, a la hora de guardar crea una instancia de esta clase, llena los datos de dicha instancia con valores inventados (en tu juego vos tendrás que llenarlos de alguna manera) y para cargarlos simplemente los imprime, igual con ver el mismo archivo debería alcanzar.

 


//Esto es para probar!
void Start()
{	
	SaveGame();
	LoadGame();
}



//Clase contenedora de datos a guardar/cargar
[System.Serializable]
public class JSONData
{
    public Vector3 pos;
    public int color;
    public string nombre;
}
    

    public void SaveGame()
    {
        
		JSONData data = new JSONData();
        string jsonString = string.Empty;

        //-------------------       
        //Aca llenas data con pos, color , etc
        //-------------------  
		data.pos = Vector3.one;
		data.color = 14;
		data.nombre = "pepe";

		//Se pasa el data al JSON (una string)
		//tiene el prettyprint en On, significa que le mete espacios en cada salto de linea
		//...para que quede lindo, de ahí el pretty
		
		jsonString = JsonUtility.ToJson(data, true);

        //Se chequea si el dir existe o no(se crea)
		//revisas la ruta a guardar (aca se debería guardar en /Assets/Profiles, porque lo tenía así, podés guardarlo donde quieras)
		
		string savePath = Application.dataPath + "/Profiles/";

        if (!Directory.Exists(savePath))
            Directory.CreateDirectory(savePath);

        
		//Se escribe el texto en el archivo destino "profile.json"
		File.WriteAllText(savePath + "profile.json", jsonString);

        Debug.Log("Juego guardado");
                
    }

    public void LoadGame()
    {
        JSONData data = new JSONData();
        string savePath = Application.dataPath + "/Profiles/";
        string filePath = savePath + "profile.json";

        if (!Directory.Exists(savePath))
            return;

        if (!File.Exists(filePath))
            return;

        string jsonString = File.ReadAllText(filePath);

        JsonUtility.FromJsonOverwrite(jsonString, data);
		
		//-------------------       
        //Aca tomas de data pos, color y nombre, y los imprimis, solo a modo de prueba
        //-------------------  
		
		Debug.Log("Pos = " + data.pos + " -- Color = " + data.color + " -- Nombre = " + data.nombre );
    }
        

Tené cuidado que mucho lo escribí aca, es código adaptado, asi que puede haber errores o cosas perdidas por ahí. Lo único que deberías hacer es llamar SaveGame o LoadGame, aca lo puse en Start a modo de prueba pero en el juego vos lo llamas desde un manager, o cualquier lado, en el momento que desees.

Edited by lightbug
copy paste fail

Share this post


Link to post
Share on other sites
hace 18 minutos, lightbug said:

Yo lo veo algo asi, esto es muy básico de Json pero debería funcionar....

estupendo y sencillo ejemplo! recomendable para todos los que esten iniciandose

 

hace 20 minutos, lightbug said:

Tené cuidado que mucho lo escribí aca, es código adaptado, asi que puede haber errores o cosas perdidas por ahí....

no lo revise a fondo, ni lo he testeado, pero parece correcto...

Share this post


Link to post
Share on other sites

En ese archivo solo hay una, pero eso fue una prueba de guardar solo el string. En mi anterior respuesta copio el archivo guardando la posicion y con el string y el int en blanco

Share this post


Link to post
Share on other sites

Ayer estuve combinando ese codigo con el que ya tenia hasta que funciono, solo acabe la parte de Guardar, ahora estoy con el Cargado. Muchas gracias por la ayuda. El problema estaba basicamente dentro de la clase serializable. Ademas es mucho mejor que se guarde todo en un solo archivo, gracias otra vez. Voy a seguir.

Saludos

Share this post


Link to post
Share on other sites

Vale, otro problema, para variar xD. Cuando cargo los datos me devuelve null. He estado repasando el código y no entiendo como se vuelve a convertir el json string en varios elementos de una lista. ¿No habría que convertir la lista en array antes de guardar o algo asi?.

Paso el código por si tengo algo mal:

 

void Update () {
.
.
.

// Carga la info desde el archivo
		if (Input.GetKeyDown (KeyCode.L)) {
			var datos = new DirectoryInfo (Application.persistentDataPath + "/MarkerData/");
			markerList = GameObject.FindGameObjectsWithTag ("Marcador");

			//Eliminar marcadores posteriores no guardados
			if (datos != null) {
				for (int i = 0; i < markerList.Length; i++) {
					Destroy (markerList [i]);
				}

				//Cargar posicion de los Marcadores

				lisData = CargaMarca ("MarkerData");
				print (lisData.lista.Count + "marcadores cargados");
/*				
                if (lisData == null) {
					print ("No se encontró el archivo");
				} else {
					print (lisData.lista [0] );
					print (lisData.lista [1] );
					for(int i=0; i< ; i++){
						marcador = Instantiate (marcadorPrefab, lisData[i].posicion, Quaternion.identity) as GameObject;	
						Marcadores.contador += 1;
							
						//print ("cargado desde archivo " + position.posicion ().ToString ());
					}
				}*/
			}
		}
}

	//Cargar posicion de los Marcadores
	listaDatos CargaMarca(string nombreArchivo) {
		if (File.Exists (nombreArchivo)) {
			BinaryFormatter bufferData = new BinaryFormatter ();
			FileStream archivo = File.Open (Application.persistentDataPath + "/MarkerData/" + nombreArchivo, FileMode.Open);
			listaDatos loadedData = JsonUtility.FromJson<listaDatos> ((string)bufferData.Deserialize (archivo));
			archivo.Close ();
			return loadedData;
		} else {
			return null;
		}
	}

Editado: Justo despues de cargar, el print (linea 81) me da null:

NullReferenceException: Object reference not set to an instance of an object
SaveLoadM.Update () (at Assets/Scripts/SaveLoadM.cs:81)

Edited by Auronity

Share this post


Link to post
Share on other sites

Este es el codigo entero, sigo sin ver el fallo:

 

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

public class SaveLoadM : MonoBehaviour {

	public GameObject marcadorPrefab;
	GameObject marcador;

	//Para la posicion de los marcadores
	public GameObject[] markerList;

	[System.Serializable]
	public class dataPCN {
		public Vector3 posicion;
		public int color;
		public string nombre;

		public dataPCN (Vector3 posicion, int color, string nombre){
			this.posicion = posicion;
			this.color = color;
			this.nombre = nombre;
		}
	}

	public class listaDatos {
		public List<dataPCN> lista = new List<dataPCN> ();
	}

	listaDatos lisData = new listaDatos();


	void Update () {
		// Guarda la info al archivo "data" y la envía a la consola
		if (Input.GetKeyDown (KeyCode.S)) {
			//Eliminar datos existentes / Resetea la carpeta
			if (Directory.Exists (Application.persistentDataPath + "/MarkerData/")) {
				Directory.Delete (Application.persistentDataPath + "/MarkerData/", true);
				Directory.CreateDirectory (Application.persistentDataPath + "/MarkerData/");
			} else {
				Directory.CreateDirectory (Application.persistentDataPath + "/MarkerData/");
			}

			markerList = GameObject.FindGameObjectsWithTag ("Marcador");

			//Guardar posicion de los Marcadores
			for(int i=0; i<markerList.Length; i++){
				//Renombrar marcadores
				markerList[i].name="Marcador " + (i+1);

				//Añadir a la lista
				lisData.lista.Add(new dataPCN(markerList[i].transform.position, 
					markerList[i].GetComponent<GestorMarcadores>().saveColor, 
					markerList[i].GetComponent<GestorMarcadores>().nuevoNombre));
				
				//print ("guardado en archivo " + position[i].posicion ().ToString ());
			}

			GuardaMarca ("MarkData", lisData);
			print (lisData.lista.Count + " marcador/es guardados");
		}

		// Carga la info desde el archivo
		if (Input.GetKeyDown (KeyCode.L)) {
			var datos = new DirectoryInfo (Application.persistentDataPath + "/MarkerData/");

			//Eliminar marcadores posteriores no guardados
			markerList = GameObject.FindGameObjectsWithTag ("Marcador");
			if (datos != null) {
				for (int i = 0; i < markerList.Length; i++) {
					Destroy (markerList [i]);
				}

				//Cargar posicion de los Marcadores
				listaDatos lisData = CargaMarca ("MarkData");
				//print ("marcadores cargados");
				if (lisData == null) {
					print ("Null");
				} else {
					print ("No null");
					/*for(int i=0; i< ; i++){
						marcador = Instantiate (marcadorPrefab, lisData[i].posicion, Quaternion.identity) as GameObject;	
						Marcadores.contador += 1;
							
						//print ("cargado desde archivo " + position.posicion ().ToString ());
					}*/
				}
			}
		}
	}


	//Guardar posicion de los Marcadores
	void GuardaMarca(string nombreArchivo, listaDatos pcn) {
		BinaryFormatter bufferData = new BinaryFormatter();
		FileStream archivo = File.Create (Application.persistentDataPath + "/MarkerData/" + nombreArchivo);
		bufferData.Serialize(archivo, JsonUtility.ToJson(pcn));
		archivo.Close();
	}

	//Cargar posicion de los Marcadores
	listaDatos CargaMarca(string nombreArchivo) {
		if (File.Exists (nombreArchivo)) {
			BinaryFormatter bufferData = new BinaryFormatter ();
			FileStream archivo = File.Open (Application.persistentDataPath + "/MarkerData/" + nombreArchivo, FileMode.Open);
			listaDatos loadedData = JsonUtility.FromJson<listaDatos> ((string)bufferData.Deserialize (archivo));
			archivo.Close ();
			return loadedData;
		} else {
			return null;
		}
	}
}

Al cargar siempre devuelve Null.

Share this post


Link to post
Share on other sites
hace 2 horas, gZone said:

Deberías dejar la comida basura y pasarte a la dieta vegana ...

...pero esta tan rica... quedate tu con la ensalada que yo me como la BigKingXXL:6_smile:

...de todas formas lo de "guardar" lo vengo haciendo en un txt desde mis origenes en la programacion... (obviamante no le pongo estension ".txt") ...y continuare haciendolo asi hasta que no me quede otro remedio...

Share this post


Link to post
Share on other sites
hace 17 horas, gZone said:

primero, al guardar ¿por qué creas y borras de modo repetitivo el archivo/carpeta?

Eso lo hacia cuando cada marcador se guardaba en un archivo, si en un guardado previo había 6 marcadores y luego reseteo y guardo 3, los 3 que sobran los eliminaba así. Pero ya esa parte no me hace falta.

Ahora probare con el código que me has pasado, creo que ya debería funcionar.

Gracias

Share this post


Link to post
Share on other sites

Perfecto, ya se cargan los marcadores. Solo me queda añadir que se le asigne a cada uno el color y el nombre guardado. Si tengo algun problema ya me pasare por aqui

Gracias otra vez.

Share this post


Link to post
Share on other sites

Ya funciona perfectamente, a falta de un par de detalles que quiero pulir. Incluso se ha solucionado un error que tenia: cuando creaba el .exe en build settings y lo probaba, al cargar, no instanciaba los marcadores, cuando en Unity si lo hacia. Pero ya funciona todo perfectamente

Muchas gracias por la ayuda

Share this post


Link to post
Share on other sites

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...