2015-09-15 17:37:28 +10:00

158 lines
5.3 KiB
C#

// Part of fCraft | Copyright (c) 2009-2014 Matvei Stefarov <me@matvei.org> | BSD-3 | See LICENSE.txt
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
namespace ClassicalSharp {
public sealed class MapFcm3 {
const uint Identifier = 0x0FC2AF40;
const byte Revision = 13;
public static byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) {
BinaryReader reader = new BinaryReader( stream );
if( reader.ReadInt32() != Identifier || reader.ReadByte() != Revision ) {
throw new InvalidDataException( "Unexpected constant in .fcm file" );
}
width = reader.ReadInt16();
height = reader.ReadInt16();
length = reader.ReadInt16();
int posX = reader.ReadInt32();
int posY = reader.ReadInt32();
int posZ = reader.ReadInt32();
byte yaw = reader.ReadByte();
byte pitch = reader.ReadByte();
reader.ReadUInt32(); // date modified
reader.ReadUInt32(); // date created
reader.ReadBytes( 16 ); // guid
reader.ReadBytes( 26 ); // layer index
int metaSize = reader.ReadInt32();
using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Decompress ) ) {
reader = new BinaryReader( ds );
for( int i = 0; i < metaSize; i++ ) {
string group = ReadString( reader );
string key = ReadString( reader );
string value = ReadString( reader );
if( group == "CS_Client" ) {
int valueInt = Int32.Parse( value );
switch( key ) {
case "SkyCol":
game.Map.SetSkyColour( new FastColour( valueInt ) ); break;
case "CloudsCol":
game.Map.SetCloudsColour( new FastColour( valueInt ) ); break;
case "FogCol":
game.Map.SetFogColour( new FastColour( valueInt ) ); break;
case "ClickDist":
game.LocalPlayer.ReachDistance = valueInt / 32f; break;
case "SunLight":
game.Map.SetSunlight( new FastColour( valueInt ) ); break;
case "ShadowLight":
game.Map.SetShadowlight( new FastColour( valueInt ) ); break;
case "Weather":
game.Map.SetWeather( (Weather)valueInt ); break;
case "SidesBlock":
game.Map.SetSidesBlock( (Block)valueInt ); break;
case "EdgeBlock":
game.Map.SetEdgeBlock( (Block)valueInt ); break;
}
}
Console.WriteLine( group + "," + key + "," + value );
}
byte[] blocks = new byte[width * height * length];
int read = ds.Read( blocks, 0, blocks.Length );
return blocks;
}
}
public static void Save( Stream stream, Game game ) {
BinaryWriter writer = new BinaryWriter( stream );
LocalPlayer p = game.LocalPlayer;
Map map = game.Map;
writer.Write( Identifier );
writer.Write( Revision );
writer.Write( (short)map.Width );
writer.Write( (short)map.Height );
writer.Write( (short)map.Length );
writer.Write( (int)( p.SpawnPoint.X * 32 ) );
writer.Write( (int)( p.SpawnPoint.Y * 32 ) );
writer.Write( (int)( p.SpawnPoint.Z * 32 ) );
writer.Write( (byte)0 ); // spawn R
writer.Write( (byte)0 ); // spawn L
writer.Write( (uint)0 ); // date modified
writer.Write( (uint)0 ); // date created
writer.Write( new byte[16] ); // map guid
writer.Write( (byte)1 ); // layer count
long indexOffset = stream.Position;
writer.Seek( 25, SeekOrigin.Current );
writer.Write( 9 ); // meta count
int compressedLength;
long offset;
using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Compress, true ) ) {
WriteMetadata( ds, game );
offset = stream.Position;
ds.Write( map.mapData, 0, map.mapData.Length );
compressedLength = (int)( stream.Position - offset );
}
writer.BaseStream.Seek( indexOffset, SeekOrigin.Begin );
writer.Write( (byte)0 );
writer.Write( offset );
writer.Write( compressedLength );
writer.Write( 0 );
writer.Write( 1 );
writer.Write( map.mapData.Length );
}
static void WriteMetadata( Stream stream, Game game ) {
BinaryWriter writer = new BinaryWriter( stream );
LocalPlayer p = game.LocalPlayer;
Map map = game.Map;
WriteMetadataEntry( writer, "SkyCol", map.SkyCol.ToArgb() );
WriteMetadataEntry( writer, "CloudsCol", map.CloudsCol.ToArgb() );
WriteMetadataEntry( writer, "FogCol", map.FogCol.ToArgb() );
WriteMetadataEntry( writer, "ClickDist", (int)( p.ReachDistance * 32 ) );
WriteMetadataEntry( writer, "SunLight", map.Sunlight.ToArgb() );
WriteMetadataEntry( writer, "ShadowLight", map.Shadowlight.ToArgb() );
WriteMetadataEntry( writer, "Weather", (int)map.Weather );
WriteMetadataEntry( writer, "SidesBlock", (int)map.SidesBlock );
WriteMetadataEntry( writer, "EdgeBlock", (int)map.EdgeBlock );
}
static string ReadString( BinaryReader reader ) {
int length = reader.ReadUInt16();
byte[] data = reader.ReadBytes( length );
return Encoding.ASCII.GetString( data );
}
static void WriteString( BinaryWriter writer, string str ) {
byte[] data = Encoding.ASCII.GetBytes( str );
writer.Write( (ushort)data.Length );
writer.Write( data );
}
static void WriteMetadataEntry( BinaryWriter writer, string key, int value ) {
WriteString( writer, "CS_Client" );
WriteString( writer, key );
WriteString( writer, value.ToString() );
}
}
}