Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Mar 21st, 2010 | Syntax: C# | Size: 9.46 KB | Hits: 192 | Expires: Never
Copy text to clipboard
  1.         byte[] blocks;
  2.         public int widthX, widthY, height;
  3.         public Position spawn;
  4.         public Dictionary<string, string> meta = new Dictionary<string, string>();
  5.  
  6.  
  7.         public Map( World _world) {
  8.             world = _world;
  9.         }
  10.  
  11.         public Map( World _world, int _widthX, int _widthY, int _height ) : this(_world) {
  12.             widthX = _widthX;
  13.             widthY = _widthY;
  14.             height = _height;
  15.  
  16.             int blockCount = widthX * widthY * height;
  17.  
  18.             blocks = new byte[blockCount];
  19.             for( int i = 0; i < blocks.Length; i++ ) {
  20.                 blocks[i] = 0;
  21.             }
  22.         }
  23.  
  24.  
  25.         // ==== Saving ========================================================
  26.  
  27.         public bool Save( string fileName ) {
  28.             string tempFileName = fileName + "." + (new Random().Next().ToString());
  29.  
  30.             using( FileStream fs = File.Create( tempFileName ) ) {
  31.                 try {
  32.                     WriteHeader( fs );
  33.                     WriteMetadata( fs );
  34.                     WriteBlocks( fs );
  35.                 } catch( IOException ex ) {
  36.                     world.log.Log( "Map.Save: Unable to open file \"{0}\" for writing: {1}", LogType.Error, tempFileName, ex.Message );
  37.                     if( File.Exists( tempFileName ) ) {
  38.                         File.Delete( tempFileName );
  39.                     }
  40.                     return false;
  41.                 }
  42.             }
  43.             if( File.Exists( fileName ) ) {
  44.                 File.Delete( fileName );
  45.             }
  46.             File.Move( tempFileName, fileName );
  47.             world.log.Log( "Saved map succesfully to {0}", LogType.SystemActivity, fileName );
  48.             return true;
  49.         }
  50.  
  51.  
  52.         void WriteHeader( FileStream fs ) {
  53.             BinaryWriter writer = new BinaryWriter( fs );
  54.             writer.Write( Config.LevelFormatID );
  55.             writer.Write( (ushort)widthX );
  56.             writer.Write( (ushort)widthY );
  57.             writer.Write( (ushort)height );
  58.             writer.Write( (ushort)spawn.x );
  59.             writer.Write( (ushort)spawn.y );
  60.             writer.Write( (ushort)spawn.h );
  61.             writer.Write( (byte)spawn.r );
  62.             writer.Write( (byte)spawn.l );
  63.             writer.Flush();
  64.         }
  65.  
  66.  
  67.         void WriteMetadata( FileStream fs ) {
  68.             BinaryWriter writer = new BinaryWriter( fs );
  69.             writer.Write( (ushort)meta.Count );
  70.             foreach( KeyValuePair<string, string> pair in meta ) {
  71.                 WriteLengthPrefixedString( writer, pair.Key );
  72.                 WriteLengthPrefixedString( writer, pair.Value );
  73.             }
  74.             writer.Flush();
  75.         }
  76.  
  77.  
  78.         void WriteBlocks( FileStream fs ) {
  79.             byte[] compressedMap = GetCompressedCopy( false );
  80.             fs.Write( compressedMap, 0, compressedMap.Length );
  81.         }
  82.  
  83.  
  84.         void WriteLengthPrefixedString( BinaryWriter writer, string s ) {
  85.             byte[] stringData = ASCIIEncoding.ASCII.GetBytes( s );
  86.             writer.Write( (uint)stringData.Length );
  87.             writer.Write( stringData );
  88.         }
  89.  
  90.  
  91.         // ==== Loading =======================================================
  92.  
  93.  
  94.         public static Map Load( World _world, string fileName ) {
  95.             FileStream fs = null;
  96.             if( !File.Exists( fileName ) ) {
  97.                 _world.log.Log( "Map.Load: Specified file does not exist: {0}", LogType.Warning, fileName );
  98.                 return null;
  99.             }
  100.  
  101.             Map map = new Map( _world );
  102.             try {
  103.                 fs = File.OpenRead( fileName );
  104.                 if( map.ReadHeader( fs ) ) {
  105.                     map.ReadMetadata( fs );
  106.                     map.ReadBlocks( fs );
  107.                     _world.log.Log( "Loaded map succesfully from {0}", LogType.Warning, fileName );
  108.                     return map;
  109.                 } else {
  110.                     return null;
  111.                 }
  112.             } catch( EndOfStreamException ) {
  113.                 _world.log.Log( "Map.Load: Unexpected end of file - possible corruption!", LogType.Error );
  114.                 return null;
  115.             } catch( Exception ex ) {
  116.                 _world.log.Log( "Map.Load: Error trying to read from \"{0}\": {1}", LogType.Error, fileName, ex.Message );
  117.                 return null;
  118.             } finally {
  119.                 if( fs != null ) {
  120.                     fs.Close();
  121.                 }
  122.             }
  123.         }
  124.  
  125.  
  126.         // Parse the level header
  127.         bool ReadHeader( FileStream fs ) {
  128.             BinaryReader reader = new BinaryReader( fs );
  129.             try {
  130.                 // TODO: reevaluate whether i need these restrictions or not
  131.                 if( reader.ReadUInt32() != 0xFC000001 ) {
  132.                     world.log.Log( "Map.ReadHeader: Incorrect level format id (expected: {0}).", LogType.Error, Config.LevelFormatID );
  133.                     return false;
  134.                 }
  135.  
  136.                 widthX = reader.ReadUInt16();
  137.                 widthY = reader.ReadUInt16();
  138.                 height = reader.ReadUInt16();
  139.  
  140.                 spawn.x = reader.ReadInt16();
  141.                 spawn.y = reader.ReadInt16();
  142.                 spawn.h = reader.ReadInt16();
  143.                 spawn.r = reader.ReadByte();
  144.                 spawn.l = reader.ReadByte();
  145.  
  146.                 if( spawn.x > widthX * 32 || spawn.y > widthY * 32 || spawn.h > height * 32 ||
  147.                     spawn.x < 0 || spawn.y < 0 || spawn.h < 0 ) {
  148.                     world.log.Log( "Map.ReadHeader: Spawn coordinates are outside the valid range! Using center of the map instead.", LogType.Warning );
  149.                     spawn.Set( widthX / 2 * 32, widthY / 2 * 32, height / 2 * 32, 0, 0 );
  150.                 }
  151.  
  152.             } catch( FormatException ex ) {
  153.                 world.log.Log( "Map.ReadHeader: Cannot parse one or more of the header entries: {0}", LogType.Error, ex.Message );
  154.                 return false;
  155.             }
  156.             return true;
  157.  
  158.         }
  159.  
  160.  
  161.         void ReadBlocks( FileStream fs ) {
  162.             int blockCount = widthX * widthY * height;
  163.             blocks = new byte[blockCount];
  164.  
  165.             GZipStream decompressor = new GZipStream( fs, CompressionMode.Decompress );
  166.             decompressor.Read( blocks, 0, blockCount );
  167.             decompressor.Flush();
  168.         }
  169.  
  170.  
  171.         void ReadMetadata( FileStream fs ) {
  172.             BinaryReader reader = new BinaryReader( fs );
  173.             try {
  174.                 int metaSize = (int)reader.ReadUInt16();
  175.  
  176.                 for( int i = 0; i < metaSize; i++ ) {
  177.                     string key = ReadLengthPrefixedString( reader );
  178.                     string value = ReadLengthPrefixedString( reader );
  179.                     meta.Add( key, value );
  180.                 }
  181.             } catch( FormatException ex ) {
  182.                 world.log.Log( "Map.ReadHeader: Cannot parse one or more of the metadata entries: {0}", LogType.Error, ex.Message );
  183.             }
  184.         }
  185.  
  186.  
  187.         string ReadLengthPrefixedString( BinaryReader reader ) {
  188.             int length = (int)reader.ReadUInt32();
  189.             byte[] stringData = reader.ReadBytes( length );
  190.             return ASCIIEncoding.ASCII.GetString( stringData );
  191.         }
  192.  
  193.  
  194.         // zips a copy of the block array
  195.         public byte[] GetCompressedCopy( bool legacyOrder ) {
  196.             byte[] compressedData;
  197.  
  198.             using( MemoryStream stream = new MemoryStream() ) {
  199.                 using( GZipStream compressor = new GZipStream( stream, CompressionMode.Compress ) ) {
  200.  
  201.                     // for compatibility with client and MinerCPP
  202.                     if( legacyOrder ) {
  203.                         // convert block count to big-endian
  204.                         int convertedBlockCount = IPAddress.HostToNetworkOrder( blocks.Length );
  205.  
  206.                         // write block count to gzip stream
  207.                         compressor.Write( BitConverter.GetBytes( convertedBlockCount ), 0, sizeof( int ) );
  208.  
  209.                         byte[] buffer = new byte[4096];
  210.                         int offset = 0;
  211.                         for( int h = 0; h < height; h++ ) {
  212.                             for( int y = 0; y < widthY; y++ ) {
  213.                                 for( int x = 0; x < widthX; x++ ) {
  214.                                     if( offset == buffer.Length ) {
  215.                                         compressor.Write( buffer, 0, buffer.Length );
  216.                                         offset = 0;
  217.                                     }
  218.                                     buffer[offset] = GetBlock( x, y, h );
  219.                                     offset++;
  220.                                 }
  221.                             }
  222.                         }
  223.                         compressor.Write( buffer, 0, offset );
  224.  
  225.                         // for internal use
  226.                     } else {
  227.                         compressor.Write( blocks, 0, blocks.Length );
  228.                     }
  229.                 }
  230.                 compressedData = stream.ToArray();
  231.             }
  232.  
  233.             return compressedData;
  234.         }
  235.  
  236.  
  237.         // ==== Simulation ====================================================
  238.  
  239.         public int Index( int x, int y, int h ) {
  240.             return (x * widthY + y) * height + h;
  241.         }
  242.  
  243.         public void SetBlock( int x, int y, int h, Blocks type ) {
  244.             if( x < widthX && y < widthY && h < height && x >= 0 && y >= 0 && h >= 0 )
  245.                 blocks[Index( x, y, h )] = (byte)type;
  246.         }