// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using System.IO; using System.IO.Compression; namespace ClassicalSharp.Map { public sealed class MapSchematicExporter : IMapFormatExporter { public void Save( Stream stream, Game game ) { using( GZipStream wrapper = new GZipStream( stream, CompressionMode.Compress ) ) { BinaryWriter writer = new BinaryWriter( wrapper ); NbtFile nbt = new NbtFile( writer ); World map = game.World; nbt.Write( NbtTagType.Compound ); nbt.Write( "Schematic" ); nbt.Write( NbtTagType.String ); nbt.Write( "Materials" ); nbt.Write( "Classic" ); nbt.Write( NbtTagType.Int16 ); nbt.Write( "Width" ); nbt.WriteInt16( (short)map.Width ); nbt.Write( NbtTagType.Int16 ); nbt.Write( "Height" ); nbt.WriteInt16( (short)map.Height ); nbt.Write( NbtTagType.Int16 ); nbt.Write( "Length" ); nbt.WriteInt16( (short)map.Length ); WriteBlocks( nbt, map.blocks ); WriteBlockData( nbt, map.blocks ); nbt.Write( NbtTagType.List ); nbt.Write( "Entities" ); nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 ); nbt.Write( NbtTagType.List ); nbt.Write( "TileEntities" ); nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 ); nbt.Write( NbtTagType.End ); } } void WriteBlocks( NbtFile nbt, byte[] blocks ) { const int chunkSize = 64 * 1024 * 32; nbt.Write( NbtTagType.Int8Array ); nbt.Write( "Blocks" ); nbt.WriteInt32( blocks.Length ); for( int i = 0; i < blocks.Length; i += chunkSize ) { int count = Math.Min( chunkSize, blocks.Length - i ); nbt.WriteBytes( blocks, i, count ); } } void WriteBlockData( NbtFile nbt, byte[] blocks ) { const int chunkSize = 64 * 1024; byte[] chunk = new byte[chunkSize]; nbt.Write( NbtTagType.Int8Array ); nbt.Write( "Data" ); nbt.WriteInt32( blocks.Length ); for( int i = 0; i < blocks.Length; i += chunkSize ) { // All 0 so we can skip this. int count = Math.Min( chunkSize, blocks.Length - i ); nbt.WriteBytes( chunk, 0, count ); } } } }