Search code examples
arraysunity-game-enginec#-4.0save

How can I save 3-dimension array into file and load later


I'm trying to save the 3D array witch has position data of the blocks with Unity and I can't find out how to save it.

public class Block
{
    public Vector3 position;
    public short blockType;
    public byte facing;

    public Block(Vector3 pos, short t, byte f)
    {
        position = pos;
        blockType = t;
        facing = f;
    }
}

This is the block class which I stored the information about block.

public Block[,,] WorldBlock = new Block[100, 10, 100];

This is the array I want to save and it has 100000 blocks in it.


Solution

  • There are many ways how to approach this.

    One way would e.g. be Newtonsoft JSON (comes as a package via the PackageManager and even pre-installed in latest Unity versions)

    using Newtonsoft.Json;
    
    ....
    
    public Block[,,] WorldBlock = new Block[100, 10, 100];
    
    private string filePath => Path.Combine(Application.persistentDataPath, "example.json");
    
    private void Save()
    {
        var json = JsonConvert.SerializeObject(WorldBlock);
        
        File.WriteAllText(filePath, json);
    }
    
    private void Load()
    {
        if (File.Exists(filePath))
        {
            var json = File.ReadAllText(filePath);
            WorldBlock = JsonConvert.DeserializeObject<Block[,,]>(json);
        }
    
        var block = WorldBlock[1, 2, 3];
        Debug.Log($"{block.position} - {block.blockType} - {block.facing}");
    }
    

    Or - since JSON wastes a lot of character space for your use case - you could also implement you own binary serialization e.g. usingBinaryReader and BinaryWriter

    in something like e.g.

    [Serializable]
    public class Block
    {
        public Vector3 position;
        public short blockType;
        public byte facing;
    
        public Block(Vector3 pos, short t, byte f)
        {
            position = pos;
            blockType = t;
            facing = f;
        }
    
        public void Serialize(BinaryWriter writer)
        {
            writer.Write(position.x);
            writer.Write(position.y);
            writer.Write(position.z);
            
            writer.Write(blockType);
            
            writer.Write(facing);
        }
    
        public void Deserialize(BinaryReader reader)
        {
            position. x = reader.ReadSingle();
            position. y = reader.ReadSingle();
            position. z = reader.ReadSingle();
    
            blockType = reader.ReadInt16();
            
            facing = reader.ReadByte();
        }
    }
    

    and then do

    private void Save()
    {
        using (var stream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
        {
            using (var writer = new BinaryWriter(stream))
            {
                // first store the size of each dimension
                for (var i = 0; i < WorldBlock.Rank; i++)
                {
                    writer.Write(WorldBlock.GetLength(i));
                }
                
                // then serialize all blocks
                for (var i = 0; i < WorldBlock.GetLength(0); i++)
                {
                    for (var j = 0; j < WorldBlock.GetLength(1); j++)
                    {
                        for (var k = 0; k < WorldBlock.GetLength(2); k++)
                        {
                            var block = WorldBlock[i, j, k];
                            block.Serialize(writer);
                        }
                    }
                }
            }
        }
    }
    
    private void Load()
    {
        if (File.Exists(filePath))
        {
            using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
            {
                using (var reader = new BinaryReader(stream))
                {
                    // first get th size of each dimension
                    var x = reader.ReadInt32();
                    var y = reader.ReadInt32();
                    var z = reader.ReadInt32();
    
                    WorldBlock = new Block[x, y, z];
    
                    // then deserialize all blocks
                    for (var i = 0; i < WorldBlock.GetLength(0); i++)
                    {
                        for (var j = 0; j < WorldBlock.GetLength(1); j++)
                        {
                            for (var k = 0; k < WorldBlock.GetLength(2); k++)
                            {
                                var block = new Block();
                                block.Deserialize(reader);
    
                                WorldBlock[i, j, k] = block;
                            }
                        }
                    }
                }
            }
        }
    
        var exampleBlock = WorldBlock[1, 2, 3];
        Debug.Log($"{exampleBlock.position} - {exampleBlock.blockType} - {exampleBlock.facing}");
    }