- Home /
Bool array to binaryformatter method
I'm making an inventory asset for my game Voidkeeper( and to possibly sell on the asset store), and I'm running into a hitch saving bool arrays.
I know I can use ArrayPrefs2, but as I'm also learning a lot from the things I want to implement for uses in other functionality, I'd like help stepping through converting my bool array "equippedBools" to be serialized by binaryformatter, so bear with me.
I came across this example for a single bool:
PlayerPrefs.SetInt(Convert.ToInt32(someBool));
Now I'm trying to understand how to do it for an entire array, using binaryformatter.
(Mike Talbot, aka Whydoit, if you read this, know I thoroughly enjoyed your UnityGems Tutorial covering this subject.).;)
Here's a code snippet from my script where I am using a proxy bool array to set values in my Items class, which works btw, just need to save and load the bool array, rather than save my items class so I can keep their texture2D, and game objects intact.:
(I need the method to save and load for the bool array, as the snippet only shows an attempt for the item class.)
public List<Items> itemsInGame = new List<Items>();
private int itemInGameCount = 0;
public bool[] equippedBools = new bool[]{};
// Use this for initialization
void Start() {
//Clear equipment list.
equippedList.Clear ();
itemInGameCount = itemsInGame.Count;
equippedBools = new bool[itemInGameCount];
//Get the data
var data = PlayerPrefs.GetString("EquipmentBools");
// //If not blank then load it
if(!string.IsNullOrEmpty(data))
{
//Binary formatter for loading back
var b = new BinaryFormatter();
//Create a memory stream with the data
var m = new MemoryStream(Convert.FromBase64String(data));
//Load back the equipped values in all the Items in game.
for(int t = 0; t < itemsInGame.Count; t++){
itemsInGame[t].equipped = b.Deserialize(m);
}
}
foreach(Items n in itemsInGame){
if(n.equipped == true){
equippedList.Add (n);
}
}
for(int t = 0; t < itemsInGame.Count; t++){
equippedBools[t] = itemsInGame[t].equipped;
}
foreach (bool value in equippedBools)
{
Debug.Log(""+ value);
}
void SaveEquipment () {
//Get a binary formatter
var b = new BinaryFormatter();
//Create an in memory stream
var m = new MemoryStream();
//Save the equipment in equippedlist.
b.Serialize(m, itemsInGame);
//Add it to player prefs
PlayerPrefs.SetString("EquipmentList", Convert.ToBase64String(m.GetBuffer()));
}
Thanks for your time.
Format your code a bit better - the indentation is making it very hard to read it...
sorry it was indented when I copy pasted I don't know what happened.
I went back and reformatted it for ya, once again I apologize.
Answer by vexe · Sep 13, 2014 at 06:51 AM
I would serialize the whole array to a string, and store that in the player prefs. Here's some extensions:
public static class BinaryFormatterExtensions
{
/// <summary>
/// Serializes 'value' to a string, using BinaryFormatter
/// </summary>
public static string SerializeToString<T>(this BinaryFormatter formatter, T value)
{
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, value);
stream.Flush();
return Convert.ToBase64String(stream.ToArray());
}
}
/// <summary>
/// Deserializes an object of type T from the string 'data'
/// </summary>
public static T DeserializeFromString<T>(this BinaryFormatter formatter, string data)
{
return (T)DeserializeFromString(formatter, data);
}
/// <summary>
/// Deserializes the serialized string 'data' back to a raw untyped System.Object
/// </summary>
public static object DeserializeFromString(this BinaryFormatter formatter, string data)
{
byte[] bytes = Convert.FromBase64String(data);
using (var stream = new MemoryStream(bytes))
return formatter.Deserialize(stream);
}
}
Usage:
var input = new bool[] { true, false, true, true, etc };
var serializer = new BinaryFormatter();
var serializedData = serializer.SerializeToString(input);
PlayerPrefs.SetString("Player Data", serializedData);
// later on...
string playerData = PlayerPrefs.GetString("Player Data");
bool[] data = serializer.DeserializeFromString<bool[]>(playerData);
You can use these methods to [de]serialize anything, not just bool[]
(except UnityEngine.Objects
of course...)
EDIT:
So this way you could take a stream as a parameter when serializing so you could serialize to memory or file:
/// <summary>
/// Serializes 'value' to a string, using BinaryFormatter from the specified stream
/// </summary>
public static string SerializeToString<T>(T value, BinaryFormatter formatter, Stream stream)
{
using (stream)
{
formatter.Serialize(stream, value);
stream.Flush();
byte[] bytes;
var ms = stream as MemoryStream;
if (ms == null)
{
var fs = stream as FileStream;
if (fs == null)
throw new NotSupportedException(string.Format("The type of stream: {0} is not supported", stream.GetType().Name));
bytes = File.ReadAllBytes(fs.Name);
}
else bytes = ms.ToArray();
return Convert.ToBase64String(bytes);
}
Notice it's a bit more complex because the base Stream
class doesn't have a ToArray
or ToBytes
or something similar to read all the bytes so I first cast to a memory stream, if the cast is successful I use the ToArray
otherwise I try file stream, if the cast is successful I read all the bytes from the original file's location (via the Name
property) otherwise I throw an exception that the stream type is not supported (you might want to add other types of streams but memory and file are the most common) - Note you might wanna be careful when loading large files like that, not the best way.
Of course there's other ways to get the bytes, see this for instance. Up to you
EDIT: So here's how you go back and forth between bool[]
and int
- kinda fun:
/// <summary>
/// Ex: [true, true, false, false] ->
/// [1, 1, 0, 0] ->
/// 12 (in decimal)
/// </summary>
public static int ToInt(this IEnumerable<bool> input)
{
var builder = new StringBuilder();
foreach (var x in input)
{
builder.Append(Convert.ToByte(x)); // true -> 1, false -> 0
}
return Convert.ToInt32(builder.ToString(), 2); // 2 is the base - cause we're converting from base 2 (binary)
}
/// <summary>
/// Credits: http://stackoverflow.com/questions/4448063/how-can-i-convert-an-int-to-an-array-of-bool
/// </summary>
public static bool[] ToBooleanArray(this int input)
{
return Convert.ToString(input, 2).Select(s => s.Equals('1')).ToArray();
}
Usage:
bool[] bools = { true, true, false, false };
int n = bools.ToInt(); // 12
foreach(var x in n.ToBooleanArray())
Debug.Log(x); // true, true, false, false
Make sure to add using System.Linq;
for the Select
method
Sure glad to help. Not sure what you mean with "convert it to integer" - you mean the byte[]
to integer? - well, an Int32
consist of 4 bytes so if you want to convert to an int you need to have an array of bytes with length of 4. See this. $$anonymous$$aybe I didn't get you. What's wrong with string?
$$anonymous$$y bad, corrected them. I was returning a raw object and taking no generic arguments. Added the generic version. The untyped version is also useful, sometimes you might not know the type of object you're returning at compile-time
You could take this further and let the serialization methods take a stream parameter as well so you could read/write from other resources such as files, etc. [Edit] added to answer
Thanks vexe, these are very comprehensive answers, I wish I could give ya more upvotes, so I clicked every thumbs up I could find for ya on the page.lol
Well done.